From 9ccb6e0a24cd917a4e2624f563ab1006a04bdc89 Mon Sep 17 00:00:00 2001 From: Kacper Ziubryniewicz Date: Mon, 1 Mar 2021 22:42:15 +0100 Subject: [PATCH 001/113] Librus 2021 Hack Working 100% Legit. --- .../ui/modules/login/LoginChooserFragment.kt | 5 ++ .../ui/modules/login/LoginLibrusFragment.kt | 53 +++++++++++++++++++ .../main/res/layout/login_librus_fragment.xml | 20 +++++++ app/src/main/res/navigation/nav_login.xml | 9 ++++ 4 files changed, 87 insertions(+) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginLibrusFragment.kt create mode 100644 app/src/main/res/layout/login_librus_fragment.xml diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginChooserFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginChooserFragment.kt index ac1bdd3b..4984eddf 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginChooserFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginChooserFragment.kt @@ -201,6 +201,11 @@ class LoginChooserFragment : Fragment(), CoroutineScope { return } + if (loginType.loginType == LOGIN_TYPE_LIBRUS) { + nav.navigate(R.id.loginLibrusFragment, null, activity.navOptions) + return + } + launch { if (!checkAvailability(loginType.loginType)) return@launch diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginLibrusFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginLibrusFragment.kt new file mode 100644 index 00000000..46b345e6 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginLibrusFragment.kt @@ -0,0 +1,53 @@ +/* + * Copyright (c) Kacper Ziubryniewicz 2021-3-1 + */ + +package pl.szczodrzynski.edziennik.ui.modules.login + +import android.net.Uri +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.databinding.LoginLibrusFragmentBinding +import kotlin.coroutines.CoroutineContext + +class LoginLibrusFragment : Fragment(), CoroutineScope { + companion object { + private const val TAG = "LoginLibrusFragment" + } + + private lateinit var app: App + private lateinit var activity: LoginActivity + private lateinit var b: LoginLibrusFragmentBinding + + private val job: Job = Job() + override val coroutineContext: CoroutineContext + get() = job + Dispatchers.Main + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + activity = (getActivity() as LoginActivity?) ?: return null + context ?: return null + app = activity.application as App + b = LoginLibrusFragmentBinding.inflate(inflater) + return b.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + b.librus2021HackWorking100PercentLegit.apply { + setVideoURI(Uri.parse("https://szkolny.eu/librus.mp4")) + setMediaController(null) + requestFocus() + start() + } + } +} diff --git a/app/src/main/res/layout/login_librus_fragment.xml b/app/src/main/res/layout/login_librus_fragment.xml new file mode 100644 index 00000000..ee07781c --- /dev/null +++ b/app/src/main/res/layout/login_librus_fragment.xml @@ -0,0 +1,20 @@ + + + + + + + + + + diff --git a/app/src/main/res/navigation/nav_login.xml b/app/src/main/res/navigation/nav_login.xml index 6fb5e503..569fffa8 100644 --- a/app/src/main/res/navigation/nav_login.xml +++ b/app/src/main/res/navigation/nav_login.xml @@ -22,6 +22,9 @@ + + + + + Date: Thu, 4 Mar 2021 22:15:51 +0100 Subject: [PATCH 002/113] [Login] Add logging Firebase events on login. --- .../edziennik/ui/modules/login/LoginChooserFragment.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginChooserFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginChooserFragment.kt index 4984eddf..4b88b4e6 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginChooserFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginChooserFragment.kt @@ -20,6 +20,7 @@ import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.google.firebase.analytics.FirebaseAnalytics import kotlinx.coroutines.* import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.api.* @@ -202,6 +203,7 @@ class LoginChooserFragment : Fragment(), CoroutineScope { } if (loginType.loginType == LOGIN_TYPE_LIBRUS) { + FirebaseAnalytics.getInstance(activity).logEvent("librus_hacked", Bundle()) nav.navigate(R.id.loginLibrusFragment, null, activity.navOptions) return } From 147f4c39e5419ab4028b4155eaba17164a25a043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 4 Mar 2021 22:27:50 +0100 Subject: [PATCH 003/113] [4.6.1] Update build.gradle, signing and changelog. --- app/src/main/assets/pl-changelog.html | 10 ++-------- app/src/main/cpp/szkolny-signing.cpp | 2 +- .../edziennik/data/api/szkolny/interceptor/Signing.kt | 2 +- build.gradle | 4 ++-- 4 files changed, 6 insertions(+), 12 deletions(-) diff --git a/app/src/main/assets/pl-changelog.html b/app/src/main/assets/pl-changelog.html index 1db852ec..2850871b 100644 --- a/app/src/main/assets/pl-changelog.html +++ b/app/src/main/assets/pl-changelog.html @@ -1,12 +1,6 @@ -

Wersja 4.6, 2021-02-26

+

Wersja 4.6.1, 2021-03-04

    -
  • Vulcan: aplikacja Szkolny.eu zaktualizowana w związku z wygaszeniem aplikacji Dzienniczek+.
  • -
  • Vulcan: dodano wyświetlanie szczęśliwego numerka.
  • -
  • Vulcan: dodano możliwość logowania adresem e-mail lub nazwą użytkownika - wersja testowa.
  • -
  • Vulcan: usunięto wyświetlanie zadań domowych i sprawdzianów z poprzednich lat.
  • -
  • Mobidziennik: naprawiono otwieranie wysłanej wiadomości.
  • -
  • Mobidziennik: poprawiono wyświetlanie oraz liczenie e-obecności.
  • -
  • iDziennik: usunięto dziennik w związku z wygaszeniem systemu. [*]
  • +
  • Przywrócono obsługę dziennika Librus Synergia.


diff --git a/app/src/main/cpp/szkolny-signing.cpp b/app/src/main/cpp/szkolny-signing.cpp index 474d9ba5..df2ca9d7 100644 --- a/app/src/main/cpp/szkolny-signing.cpp +++ b/app/src/main/cpp/szkolny-signing.cpp @@ -9,7 +9,7 @@ /*secret password - removed for source code publication*/ static toys AES_IV[16] = { - 0x9f, 0xff, 0x0f, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + 0xdc, 0x61, 0x4d, 0x5b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat); diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt index b67ef993..5e706467 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt @@ -46,6 +46,6 @@ object Signing { /*fun provideKey(param1: String, param2: Long): ByteArray {*/ fun pleaseStopRightNow(param1: String, param2: Long): ByteArray { - return "$param1.MTIzNDU2Nzg5MDgzuDTD2K===.$param2".sha256() + return "$param1.MTIzNDU2Nzg5MDAXOgN264===.$param2".sha256() } } diff --git a/build.gradle b/build.gradle index 7e2c6a5a..c0fb9910 100644 --- a/build.gradle +++ b/build.gradle @@ -5,8 +5,8 @@ buildscript { kotlin_version = '1.4.30' release = [ - versionName: "4.6", - versionCode: 4060099 + versionName: "4.6.1", + versionCode: 4060199 ] setup = [ From 50e7bf14d45c7d98d6be2e8931e6f3526e9dcd42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 20 Mar 2021 18:03:12 +0100 Subject: [PATCH 004/113] [Gradle] Extract material-about-library dependency. --- app/build.gradle | 2 +- .../modules/settings/SettingsNewFragment.java | 240 +++---- app/src/main/res/values/styles.xml | 6 - material-about-library/build.gradle | 38 -- .../src/main/AndroidManifest.xml | 4 - .../ConvenienceBuilder.java | 357 ----------- .../MaterialAboutActivity.java | 186 ------ .../MaterialAboutFragment.java | 132 ---- .../adapters/MaterialAboutItemAdapter.java | 167 ----- .../adapters/MaterialAboutListAdapter.java | 237 ------- .../holders/MaterialAboutItemViewHolder.java | 12 - .../items/MaterialAboutActionItem.java | 488 -------------- .../items/MaterialAboutActionSwitchItem.java | 606 ------------------ .../items/MaterialAboutCheckboxItem.java | 538 ---------------- .../items/MaterialAboutItem.java | 23 - .../MaterialAboutItemOnChangeAction.java | 5 - .../items/MaterialAboutItemOnClickAction.java | 5 - .../items/MaterialAboutProfileItem.java | 352 ---------- .../items/MaterialAboutSwitchItem.java | 548 ---------------- .../items/MaterialAboutTitleItem.java | 400 ------------ .../model/MaterialAboutCard.java | 156 ----- .../model/MaterialAboutList.java | 45 -- .../util/DefaultViewTypeManager.java | 108 ---- .../util/OpenSourceLicense.java | 22 - .../util/ViewTypeManager.java | 35 - .../layout/mal_material_about_action_item.xml | 58 -- .../mal_material_about_action_switch_item.xml | 83 --- .../layout/mal_material_about_activity.xml | 33 - .../mal_material_about_checkbox_item.xml | 65 -- .../layout/mal_material_about_fragment.xml | 14 - .../layout/mal_material_about_list_card.xml | 54 -- .../mal_material_about_profile_item.xml | 66 -- .../layout/mal_material_about_switch_item.xml | 67 -- .../layout/mal_material_about_title_item.xml | 60 -- .../src/main/res/values/attrs.xml | 10 - .../src/main/res/values/colors.xml | 8 - .../src/main/res/values/dimens.xml | 16 - .../src/main/res/values/strings.xml | 94 --- .../src/main/res/values/styles.xml | 17 - settings.gradle | 2 +- 40 files changed, 108 insertions(+), 5251 deletions(-) delete mode 100644 material-about-library/build.gradle delete mode 100644 material-about-library/src/main/AndroidManifest.xml delete mode 100644 material-about-library/src/main/java/com/danielstone/materialaboutlibrary/ConvenienceBuilder.java delete mode 100644 material-about-library/src/main/java/com/danielstone/materialaboutlibrary/MaterialAboutActivity.java delete mode 100644 material-about-library/src/main/java/com/danielstone/materialaboutlibrary/MaterialAboutFragment.java delete mode 100644 material-about-library/src/main/java/com/danielstone/materialaboutlibrary/adapters/MaterialAboutItemAdapter.java delete mode 100644 material-about-library/src/main/java/com/danielstone/materialaboutlibrary/adapters/MaterialAboutListAdapter.java delete mode 100644 material-about-library/src/main/java/com/danielstone/materialaboutlibrary/holders/MaterialAboutItemViewHolder.java delete mode 100644 material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutActionItem.java delete mode 100644 material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutActionSwitchItem.java delete mode 100644 material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutCheckboxItem.java delete mode 100644 material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutItem.java delete mode 100644 material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutItemOnChangeAction.java delete mode 100644 material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutItemOnClickAction.java delete mode 100644 material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutProfileItem.java delete mode 100644 material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutSwitchItem.java delete mode 100644 material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutTitleItem.java delete mode 100644 material-about-library/src/main/java/com/danielstone/materialaboutlibrary/model/MaterialAboutCard.java delete mode 100644 material-about-library/src/main/java/com/danielstone/materialaboutlibrary/model/MaterialAboutList.java delete mode 100644 material-about-library/src/main/java/com/danielstone/materialaboutlibrary/util/DefaultViewTypeManager.java delete mode 100644 material-about-library/src/main/java/com/danielstone/materialaboutlibrary/util/OpenSourceLicense.java delete mode 100644 material-about-library/src/main/java/com/danielstone/materialaboutlibrary/util/ViewTypeManager.java delete mode 100644 material-about-library/src/main/res/layout/mal_material_about_action_item.xml delete mode 100644 material-about-library/src/main/res/layout/mal_material_about_action_switch_item.xml delete mode 100644 material-about-library/src/main/res/layout/mal_material_about_activity.xml delete mode 100644 material-about-library/src/main/res/layout/mal_material_about_checkbox_item.xml delete mode 100644 material-about-library/src/main/res/layout/mal_material_about_fragment.xml delete mode 100644 material-about-library/src/main/res/layout/mal_material_about_list_card.xml delete mode 100644 material-about-library/src/main/res/layout/mal_material_about_profile_item.xml delete mode 100644 material-about-library/src/main/res/layout/mal_material_about_switch_item.xml delete mode 100644 material-about-library/src/main/res/layout/mal_material_about_title_item.xml delete mode 100644 material-about-library/src/main/res/values/attrs.xml delete mode 100644 material-about-library/src/main/res/values/colors.xml delete mode 100644 material-about-library/src/main/res/values/dimens.xml delete mode 100644 material-about-library/src/main/res/values/strings.xml delete mode 100644 material-about-library/src/main/res/values/styles.xml diff --git a/app/build.gradle b/app/build.gradle index 880d6f0f..0c95ebd6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -169,7 +169,7 @@ dependencies { implementation project(":agendacalendarview") implementation project(":cafebar") - implementation project(":material-about-library") + implementation "eu.szkolny:material-about-library:0534abf316" implementation project(":mhttp") implementation project(":nachos") //implementation project(":Navigation") diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java index 555bc3fd..e1541d54 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java @@ -21,7 +21,6 @@ import com.danielstone.materialaboutlibrary.items.MaterialAboutActionItem; import com.danielstone.materialaboutlibrary.items.MaterialAboutActionSwitchItem; import com.danielstone.materialaboutlibrary.items.MaterialAboutItem; import com.danielstone.materialaboutlibrary.items.MaterialAboutItemOnClickAction; -import com.danielstone.materialaboutlibrary.items.MaterialAboutProfileItem; import com.danielstone.materialaboutlibrary.items.MaterialAboutSwitchItem; import com.danielstone.materialaboutlibrary.items.MaterialAboutTitleItem; import com.danielstone.materialaboutlibrary.model.MaterialAboutCard; @@ -156,12 +155,12 @@ public class SettingsNewFragment extends MaterialAboutFragment { roundDrawable.setCircular(true); return roundDrawable;*/ } - private MaterialAboutProfileItem profileCardTitleItem; + private MaterialAboutTitleItem profileCardTitleItem; private ArrayList getProfileCard(boolean expandedOnly) { ArrayList items = new ArrayList<>(); if (!expandedOnly) { - profileCardTitleItem = new MaterialAboutProfileItem( + profileCardTitleItem = new MaterialAboutTitleItem( app.getProfile().getName(), app.getProfile().getSubname(), getProfileDrawable() @@ -267,20 +266,20 @@ public class SettingsNewFragment extends MaterialAboutFragment { else { items.add( - new MaterialAboutSwitchItem( - getString(R.string.settings_profile_sync_text), - getString(R.string.settings_profile_sync_subtext), - new IconicsDrawable(activity) + new MaterialAboutSwitchItem.Builder() + .text(R.string.settings_profile_sync_text) + .subText(R.string.settings_profile_sync_subtext) + .icon(new IconicsDrawable(activity) .icon(CommunityMaterial.Icon.cmd_account_convert) .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) - ) + .color(IconicsColor.colorInt(iconColor))) .setChecked(app.getProfile().getSyncEnabled()) - .setOnChangeAction(((isChecked, tag) -> { + .setOnCheckedChanged(((item, isChecked) -> { app.getProfile().setSyncEnabled(isChecked); app.profileSave(); return true; })) + .build() ); } @@ -300,20 +299,20 @@ public class SettingsNewFragment extends MaterialAboutFragment { Date today = Date.getToday(); if (today.month == 12 || today.month == 1) { items.add( - new MaterialAboutSwitchItem( - getString(R.string.settings_theme_snowfall_text), - getString(R.string.settings_theme_snowfall_subtext), - new IconicsDrawable(activity) + new MaterialAboutSwitchItem.Builder() + .text(R.string.settings_theme_snowfall_text) + .subText(R.string.settings_theme_snowfall_subtext) + .icon(new IconicsDrawable(activity) .icon(CommunityMaterial.Icon2.cmd_snowflake) .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) - ) + .color(IconicsColor.colorInt(iconColor))) .setChecked(app.getConfig().getUi().getSnowfall()) - .setOnChangeAction((isChecked, tag) -> { + .setOnCheckedChanged((item, isChecked) -> { app.getConfig().getUi().setSnowfall(isChecked); activity.recreate(); return true; }) + .build() ); } @@ -343,24 +342,24 @@ public class SettingsNewFragment extends MaterialAboutFragment { ); items.add( - new MaterialAboutSwitchItem( - getString(R.string.settings_theme_mini_drawer_text), - getString(R.string.settings_theme_mini_drawer_subtext), - new IconicsDrawable(activity) + new MaterialAboutSwitchItem.Builder() + .text(R.string.settings_theme_mini_drawer_text) + .subText(R.string.settings_theme_mini_drawer_subtext) + .icon(new IconicsDrawable(activity) .icon(CommunityMaterial.Icon.cmd_dots_vertical) .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) - ) - .setChecked(app.getConfig().getUi().getMiniMenuVisible()) - .setOnChangeAction((isChecked, tag) -> { - // 0,1 1 - // 0,0 0 - // 1,1 0 - // 1,0 1 - app.getConfig().getUi().setMiniMenuVisible(isChecked); - activity.getNavView().drawer.setMiniDrawerVisiblePortrait(isChecked); - return true; - }) + .color(IconicsColor.colorInt(iconColor))) + .setChecked(app.getConfig().getUi().getMiniMenuVisible()) + .setOnCheckedChanged((item, isChecked) -> { + // 0,1 1 + // 0,0 0 + // 1,1 0 + // 1,0 1 + app.getConfig().getUi().setMiniMenuVisible(isChecked); + activity.getNavView().drawer.setMiniDrawerVisiblePortrait(isChecked); + return true; + }) + .build() ); items.add(getMoreItem(() -> addCardItems(CARD_THEME, getThemeCard(true)))); @@ -496,19 +495,18 @@ public class SettingsNewFragment extends MaterialAboutFragment { ); items.add( - new MaterialAboutSwitchItem( - getString(R.string.settings_theme_open_drawer_on_back_pressed_text), - null, - new IconicsDrawable(activity) + new MaterialAboutSwitchItem.Builder( ) + .text(R.string.settings_theme_open_drawer_on_back_pressed_text) + .icon(new IconicsDrawable(activity) .icon(CommunityMaterial.Icon2.cmd_menu_open) .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) - ) + .color(IconicsColor.colorInt(iconColor))) .setChecked(app.getConfig().getUi().getOpenDrawerOnBackPressed()) - .setOnChangeAction((isChecked, tag) -> { + .setOnCheckedChanged((item, isChecked) -> { app.getConfig().getUi().setOpenDrawerOnBackPressed(isChecked); return true; }) + .build() ); } return items; @@ -548,20 +546,20 @@ public class SettingsNewFragment extends MaterialAboutFragment { ); } private MaterialAboutItem getSyncCardWifiItem() { - return new MaterialAboutSwitchItem( - getString(R.string.settings_sync_wifi_text), - getString(R.string.settings_sync_wifi_subtext), - new IconicsDrawable(activity) + return new MaterialAboutSwitchItem.Builder() + .text(R.string.settings_sync_wifi_text) + .subText(R.string.settings_sync_wifi_subtext) + .icon(new IconicsDrawable(activity) .icon(CommunityMaterial.Icon2.cmd_wifi_strength_2) .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) - ) + .color(IconicsColor.colorInt(iconColor))) .setChecked(app.getConfig().getSync().getOnlyWifi()) - .setOnChangeAction((isChecked, tag) -> { + .setOnCheckedChanged((item, isChecked) -> { app.getConfig().getSync().setOnlyWifi(isChecked); SyncWorker.Companion.rescheduleNext(app); return true; - }); + }) + .build(); } private MaterialAboutActionSwitchItem syncCardIntervalItem; private MaterialAboutActionSwitchItem syncCardQuietHoursItem; @@ -569,14 +567,14 @@ public class SettingsNewFragment extends MaterialAboutFragment { ArrayList items = new ArrayList<>(); if (!expandedOnly) { - syncCardIntervalItem = new MaterialAboutActionSwitchItem( - getString(R.string.settings_sync_sync_interval_text), - getString(R.string.settings_sync_sync_interval_subtext_disabled), - new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon.cmd_download_outline) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) - ); + syncCardIntervalItem = new MaterialAboutActionSwitchItem.Builder() + .text(R.string.settings_sync_sync_interval_text) + .subText(R.string.settings_sync_sync_interval_subtext_disabled) + .icon(new IconicsDrawable(activity) + .icon(CommunityMaterial.Icon.cmd_download_outline) + .size(IconicsSize.dp(iconSizeDp)) + .color(IconicsColor.colorInt(iconColor))) + .build(); syncCardIntervalItem.setSubTextChecked(getSyncCardIntervalSubText()); syncCardIntervalItem.setChecked(app.getConfig().getSync().getEnabled()); syncCardIntervalItem.setOnClickAction(() -> { @@ -625,7 +623,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { }) .show(); }); - syncCardIntervalItem.setOnChangeAction((isChecked, tag) -> { + syncCardIntervalItem.setOnCheckedChangedAction((item, isChecked) -> { if (isChecked && !app.getConfig().getSync().getEnabled()) { addCardItem(CARD_SYNC, 1, getSyncCardWifiItem()); } @@ -660,14 +658,14 @@ public class SettingsNewFragment extends MaterialAboutFragment { );*/ - syncCardQuietHoursItem = new MaterialAboutActionSwitchItem( - getString(R.string.settings_sync_quiet_hours_text), - getString(R.string.settings_sync_quiet_hours_subtext_disabled), - new IconicsDrawable(activity) + syncCardQuietHoursItem = new MaterialAboutActionSwitchItem.Builder() + .text(R.string.settings_sync_quiet_hours_text) + .subText(R.string.settings_sync_quiet_hours_subtext_disabled) + .icon(new IconicsDrawable(activity) .icon(CommunityMaterial.Icon.cmd_bell_sleep_outline) .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) - ); + .color(IconicsColor.colorInt(iconColor))) + .build(); syncCardQuietHoursItem.setChecked(app.getConfig().getSync().getQuietHoursEnabled()); syncCardQuietHoursItem.setSubTextChecked(getSyncCardQuietHoursSubText()); syncCardQuietHoursItem.setOnClickAction(() -> { @@ -707,7 +705,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { }) .show(); }); - syncCardQuietHoursItem.setOnChangeAction((isChecked, tag) -> { + syncCardQuietHoursItem.setOnCheckedChangedAction((item, isChecked) -> { app.getConfig().getSync().setQuietHoursEnabled(isChecked); if (isChecked && app.getConfig().getSync().getQuietHoursStart() == null) { app.getConfig().getSync().setQuietHoursStart(new Time(22, 30, 0)); @@ -752,20 +750,19 @@ public class SettingsNewFragment extends MaterialAboutFragment { );*/ items.add( - new MaterialAboutSwitchItem( - getString(R.string.settings_sync_updates_text), - null, - new IconicsDrawable(activity) + new MaterialAboutSwitchItem.Builder() + .text(R.string.settings_sync_updates_text) + .icon(new IconicsDrawable(activity) .icon(CommunityMaterial.Icon.cmd_cellphone_arrow_down) .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) - ) + .color(IconicsColor.colorInt(iconColor))) .setChecked(app.getConfig().getSync().getNotifyAboutUpdates()) - .setOnChangeAction((isChecked, tag) -> { + .setOnCheckedChanged((item, isChecked) -> { app.getConfig().getSync().setNotifyAboutUpdates(isChecked); UpdateWorker.Companion.rescheduleNext(app); return true; }) + .build() ); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { @@ -846,16 +843,15 @@ public class SettingsNewFragment extends MaterialAboutFragment { ); } private MaterialAboutItem getRegisterCardSharedEventsItem() { - return new MaterialAboutSwitchItem( - getString(R.string.settings_register_shared_events_text), - getString(R.string.settings_register_shared_events_subtext), - new IconicsDrawable(activity) + return new MaterialAboutSwitchItem.Builder() + .text(R.string.settings_register_shared_events_text) + .subText(R.string.settings_register_shared_events_subtext) + .icon(new IconicsDrawable(activity) .icon(CommunityMaterial.Icon2.cmd_share_outline) .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) - ) + .color(IconicsColor.colorInt(iconColor))) .setChecked(app.getProfile().getEnableSharedEvents()) - .setOnChangeAction((isChecked, tag) -> { + .setOnCheckedChanged((item, isChecked) -> { app.getProfile().setEnableSharedEvents(isChecked); app.profileSave(); if (isChecked) new MaterialDialog.Builder(activity) @@ -869,7 +865,8 @@ public class SettingsNewFragment extends MaterialAboutFragment { .positiveText(R.string.ok) .show(); return true; - }); + }) + .build(); } private MaterialAboutSwitchItem registerCardAllowRegistrationItem; @@ -895,16 +892,16 @@ public class SettingsNewFragment extends MaterialAboutFragment { .color(IconicsColor.colorInt(iconColor)) ).setOnClickAction(() -> new AttendanceConfigDialog(activity, false, null, null))); - registerCardAllowRegistrationItem = new MaterialAboutSwitchItem( - getString(R.string.settings_register_allow_registration_text), - getString(R.string.settings_register_allow_registration_subtext), - new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon.cmd_account_circle_outline) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) - ); + registerCardAllowRegistrationItem = new MaterialAboutSwitchItem.Builder() + .text(R.string.settings_register_allow_registration_text) + .subText(R.string.settings_register_allow_registration_subtext) + .icon(new IconicsDrawable(activity) + .icon(CommunityMaterial.Icon.cmd_account_circle_outline) + .size(IconicsSize.dp(iconSizeDp)) + .color(IconicsColor.colorInt(iconColor))) + .build(); registerCardAllowRegistrationItem.setChecked(app.getProfile().getRegistration() == REGISTRATION_ENABLED); - registerCardAllowRegistrationItem.setOnChangeAction((isChecked, tag) -> { + registerCardAllowRegistrationItem.setOnCheckedChangedAction((item, isChecked) -> { if (isChecked) new MaterialDialog.Builder(activity) .title(getString(R.string.settings_register_allow_registration_dialog_enabled_title)) .content(getString(R.string.settings_register_allow_registration_dialog_enabled_text)) @@ -1025,55 +1022,53 @@ public class SettingsNewFragment extends MaterialAboutFragment { items.add(registerCardBellSyncItem); items.add( - new MaterialAboutSwitchItem( - getString(R.string.settings_register_count_in_seconds_text), - getString(R.string.settings_register_count_in_seconds_subtext), - new IconicsDrawable(activity) + new MaterialAboutSwitchItem.Builder() + .text(R.string.settings_register_count_in_seconds_text) + .subText(R.string.settings_register_count_in_seconds_subtext) + .icon(new IconicsDrawable(activity) .icon(CommunityMaterial.Icon2.cmd_timer) .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) - ) + .color(IconicsColor.colorInt(iconColor))) .setChecked(app.getConfig().getTimetable().getCountInSeconds()) - .setOnChangeAction((isChecked, tag) -> { + .setOnCheckedChanged((item, isChecked) -> { app.getConfig().getTimetable().setCountInSeconds(isChecked); return true; }) + .build() ); if (app.getProfile().getLoginStoreType() == LoginStore.LOGIN_TYPE_LIBRUS) { items.add( - new MaterialAboutSwitchItem( - getString(R.string.settings_register_show_teacher_absences_text), - null, - new IconicsDrawable(activity) + new MaterialAboutSwitchItem.Builder() + .text(R.string.settings_register_show_teacher_absences_text) + .icon(new IconicsDrawable(activity) .icon(CommunityMaterial.Icon.cmd_account_arrow_right_outline) .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) - ) + .color(IconicsColor.colorInt(iconColor))) .setChecked(app.getProfile().getStudentData("showTeacherAbsences", true)) - .setOnChangeAction((isChecked, tag) -> { + .setOnCheckedChanged((item, isChecked) -> { app.getProfile().putStudentData("showTeacherAbsences", isChecked); app.profileSave(); return true; }) + .build() ); } if (App.Companion.getDevMode()) { items.add( - new MaterialAboutSwitchItem( - getString(R.string.settings_register_hide_sticks_from_old), - null, - new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon2.cmd_numeric_1_box_outline) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) - ) + new MaterialAboutSwitchItem.Builder() + .text(R.string.settings_register_hide_sticks_from_old) + .icon(new IconicsDrawable(activity) + .icon(CommunityMaterial.Icon2.cmd_numeric_1_box_outline) + .size(IconicsSize.dp(iconSizeDp)) + .color(IconicsColor.colorInt(iconColor))) .setChecked(app.getConfig().forProfile().getGrades().getHideSticksFromOld()) - .setOnChangeAction((isChecked, tag) -> { + .setOnCheckedChanged((item, isChecked) -> { app.getConfig().forProfile().getGrades().setHideSticksFromOld(isChecked); return true; }) + .build() ); } @@ -1097,15 +1092,11 @@ public class SettingsNewFragment extends MaterialAboutFragment { items.add(new MaterialAboutTitleItem.Builder() .text(R.string.app_name) .desc(R.string.settings_about_title_subtext) - .textColor(primaryTextOnPrimaryBg) - .descColor(secondaryTextOnPrimaryBg) .icon(R.mipmap.ic_splash) .build()); pref_about_version = new MaterialAboutActionItem.Builder() .text(R.string.settings_about_version_text) - .textColor(primaryTextOnPrimaryBg) - .subTextColor(secondaryTextOnPrimaryBg) .subText(BuildConfig.VERSION_NAME + ", " + BuildConfig.BUILD_TYPE) .icon(new IconicsDrawable(activity) .icon(CommunityMaterial.Icon2.cmd_information_outline) @@ -1129,8 +1120,6 @@ public class SettingsNewFragment extends MaterialAboutFragment { items.add(new MaterialAboutActionItem.Builder() .text(R.string.settings_about_privacy_policy_text) - .textColor(primaryTextOnPrimaryBg) - .subTextColor(secondaryTextOnPrimaryBg) .icon(new IconicsDrawable(activity) .icon(CommunityMaterial.Icon2.cmd_shield_outline) .color(IconicsColor.colorInt(primaryTextOnPrimaryBg)) @@ -1140,8 +1129,6 @@ public class SettingsNewFragment extends MaterialAboutFragment { items.add(new MaterialAboutActionItem.Builder() .text(R.string.settings_about_discord_text) - .textColor(primaryTextOnPrimaryBg) - .subTextColor(secondaryTextOnPrimaryBg) .subText(R.string.settings_about_discord_subtext) .icon(new IconicsDrawable(activity) .icon(SzkolnyFont.Icon.szf_discord_outline) @@ -1152,8 +1139,6 @@ public class SettingsNewFragment extends MaterialAboutFragment { items.add(new MaterialAboutActionItem.Builder() .text(R.string.settings_about_language_text) - .textColor(primaryTextOnPrimaryBg) - .subTextColor(secondaryTextOnPrimaryBg) .subText(R.string.settings_about_language_subtext) .icon(new IconicsDrawable(activity) .icon(CommunityMaterial.Icon2.cmd_translate) @@ -1193,8 +1178,6 @@ public class SettingsNewFragment extends MaterialAboutFragment { items.add(new MaterialAboutActionItem.Builder() .text(R.string.settings_about_update_text) .subText(R.string.settings_about_update_subtext) - .textColor(primaryTextOnPrimaryBg) - .subTextColor(secondaryTextOnPrimaryBg) .icon(new IconicsDrawable(activity) .icon(CommunityMaterial.Icon2.cmd_update) .color(IconicsColor.colorInt(primaryTextOnPrimaryBg)) @@ -1218,8 +1201,6 @@ public class SettingsNewFragment extends MaterialAboutFragment { items.add(new MaterialAboutActionItem.Builder() .text(R.string.settings_about_changelog_text) - .textColor(primaryTextOnPrimaryBg) - .subTextColor(secondaryTextOnPrimaryBg) .icon(new IconicsDrawable(activity) .icon(CommunityMaterial.Icon2.cmd_radar) .color(IconicsColor.colorInt(primaryTextOnPrimaryBg)) @@ -1229,8 +1210,6 @@ public class SettingsNewFragment extends MaterialAboutFragment { items.add(new MaterialAboutActionItem.Builder() .text(R.string.settings_about_licenses_text) - .textColor(primaryTextOnPrimaryBg) - .subTextColor(secondaryTextOnPrimaryBg) .icon(new IconicsDrawable(activity) .icon(CommunityMaterial.Icon.cmd_code_braces) .color(IconicsColor.colorInt(primaryTextOnPrimaryBg)) @@ -1267,8 +1246,6 @@ public class SettingsNewFragment extends MaterialAboutFragment { items.add(new MaterialAboutActionItem.Builder() .text(R.string.settings_about_crash_text) .subText(R.string.settings_about_crash_subtext) - .textColor(primaryTextOnPrimaryBg) - .subTextColor(secondaryTextOnPrimaryBg) .icon(new IconicsDrawable(activity) .icon(CommunityMaterial.Icon.cmd_bug_outline) .color(IconicsColor.colorInt(primaryTextOnPrimaryBg)) @@ -1304,11 +1281,6 @@ public class SettingsNewFragment extends MaterialAboutFragment { return materialAboutList; } - @Override - protected int getTheme() { - return Themes.INSTANCE.getAppTheme(); - } - /* _____ _ ____ _ _ / ____| | | | _ \ | | | | | | _ _ ___| |_ ___ _ __ ___ | |_) | __ _ ___| | ____ _ _ __ ___ _ _ _ __ __| |___ diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 9983ecf0..512c6ade 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -111,12 +111,9 @@ ?colorAccent ?android:textColorPrimary - @style/Theme.Mal.Toolbar.Dark - @style/Theme.Mal.Toolbar.Light ?android:textColorPrimary ?android:textColorSecondary ?colorSurface - @color/dividerColor @drawable/timetable_lesson_bg_light #9f9f9f @@ -147,12 +144,9 @@ ?colorAccent ?android:textColorPrimary - @style/Theme.Mal.Toolbar.Dark - @style/Theme.Mal.Toolbar.Dark @color/primaryTextDark @color/secondaryTextDark ?colorSurface - @color/dividerColor @drawable/timetable_lesson_bg_dark #838383 diff --git a/material-about-library/build.gradle b/material-about-library/build.gradle deleted file mode 100644 index c79c427c..00000000 --- a/material-about-library/build.gradle +++ /dev/null @@ -1,38 +0,0 @@ -apply plugin: 'com.android.library' - -group = 'com.github.daniel-stoneuk' - -def versionMajor = 2 -def versionMinor = 3 -def versionPatch = 0 -def versionBuild = 0 // bump for dogfood builds, public betas, etc. - -android { - compileSdkVersion setup.compileSdk - - defaultConfig { - minSdkVersion 14 - targetSdkVersion setup.targetSdk - versionCode versionMajor * 10000 + versionMinor * 1000 + versionPatch * 100 + versionBuild - versionName "${versionMajor}.${versionMinor}" + (versionPatch == 0 ? "" : ".${versionPatch}") - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - debugMinify { - debuggable = true - minifyEnabled = true - proguardFiles 'proguard-android.txt' - } - } -} - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation "androidx.appcompat:appcompat:${versions.appcompat}" - implementation "androidx.cardview:cardview:${versions.cardview}" - implementation "com.google.android.material:material:${versions.material}" -} diff --git a/material-about-library/src/main/AndroidManifest.xml b/material-about-library/src/main/AndroidManifest.xml deleted file mode 100644 index 71d1ecd9..00000000 --- a/material-about-library/src/main/AndroidManifest.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/ConvenienceBuilder.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/ConvenienceBuilder.java deleted file mode 100644 index f0e17e95..00000000 --- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/ConvenienceBuilder.java +++ /dev/null @@ -1,357 +0,0 @@ -package com.danielstone.materialaboutlibrary; - -import android.content.ActivityNotFoundException; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.os.Build; -import androidx.annotation.Nullable; -import androidx.appcompat.app.AlertDialog; -import android.webkit.WebView; -import android.widget.Toast; - -import com.danielstone.materialaboutlibrary.items.MaterialAboutActionItem; -import com.danielstone.materialaboutlibrary.items.MaterialAboutItemOnClickAction; -import com.danielstone.materialaboutlibrary.items.MaterialAboutTitleItem; -import com.danielstone.materialaboutlibrary.model.MaterialAboutCard; -import com.danielstone.materialaboutlibrary.util.OpenSourceLicense; - -@SuppressWarnings("JavaDoc") -public class ConvenienceBuilder { - - public static MaterialAboutTitleItem createAppTitleItem(String appName, Drawable applicationIcon) { - return new MaterialAboutTitleItem(appName, null, applicationIcon); - } - - public static MaterialAboutTitleItem createAppTitleItem(Context c) { - Context applicationContext = c.getApplicationContext(); - PackageManager packageManager = applicationContext.getPackageManager(); - ApplicationInfo applicationInfo = applicationContext.getApplicationInfo(); - CharSequence appName = packageManager.getApplicationLabel(applicationInfo); - Drawable applicationIcon = packageManager.getApplicationIcon(applicationInfo); - return createAppTitleItem(appName == null ? "" : appName.toString(), applicationIcon); - } - - /** - * Creates an item with version info read from the PackageManager for current application. - * - * @param c context - * @param icon - * @param text - * @param includeVersionCode - * @return Item to add to card. - */ - public static MaterialAboutActionItem createVersionActionItem(Context c, Drawable icon, CharSequence text, boolean includeVersionCode) { - String versionName = ""; - int versionCode = 0; - try { - PackageInfo pInfo = c.getPackageManager().getPackageInfo(c.getPackageName(), 0); - versionName = pInfo.versionName; - versionCode = pInfo.versionCode; - } catch (PackageManager.NameNotFoundException ignored) { - // This shouldn't happen. - } - return new MaterialAboutActionItem.Builder() - .text(text) - .subText(versionName + (includeVersionCode ? " (" + versionCode + ")" : "")) - .icon(icon) - .build(); - } - - public static MaterialAboutItemOnClickAction createWebViewDialogOnClickAction(final Context c, final CharSequence dialogTitle, final String htmlString, final boolean isStringUrl, final boolean supportZoom) { - return createWebViewDialogOnClickAction(c, dialogTitle, c.getString(R.string.mal_close), htmlString, isStringUrl, supportZoom); - } - - public static MaterialAboutItemOnClickAction createWebViewDialogOnClickAction(final Context c, final CharSequence dialogTitle, final CharSequence dialogNegativeButton, final String htmlString, final boolean isStringUrl, final boolean supportZoom) { - - return new MaterialAboutItemOnClickAction() { - @Override - public void onClick() { - AlertDialog.Builder alertBuilder = new AlertDialog.Builder(c); - alertBuilder.setTitle(dialogTitle); - - final WebView wv = new WebView(c); - wv.getSettings().setSupportZoom(supportZoom); - if (!supportZoom) { - wv.getSettings().setLoadWithOverviewMode(true); - wv.getSettings().setUseWideViewPort(true); - } - if (isStringUrl) { - wv.loadUrl(htmlString); - } else { - wv.loadData(htmlString, "text/html; charset=utf-8", "UTF-8"); - } - - alertBuilder.setView(wv); - alertBuilder.setNegativeButton(dialogNegativeButton, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - wv.destroy(); - dialog.dismiss(); - } - }); - - final AlertDialog dialog = alertBuilder.create(); - dialog.show(); - } - }; - } - - - public static MaterialAboutActionItem createWebViewDialogItem(Context c, Drawable icon, CharSequence text, @Nullable CharSequence subText, CharSequence dialogTitle, String htmlString, boolean isStringUrl, boolean supportZoom) { - return createWebViewDialogItem(c, icon, text, subText, dialogTitle, c.getString(R.string.mal_close), htmlString, isStringUrl, supportZoom); - } - - public static MaterialAboutActionItem createWebViewDialogItem(Context c, Drawable icon, CharSequence text, @Nullable CharSequence subText, CharSequence dialogTitle, CharSequence dialogNegativeButton, String htmlString, boolean isStringUrl, boolean supportZoom) { - return new MaterialAboutActionItem.Builder() - .text(text) - .subText(subText) - .icon(icon) - .setOnClickAction(createWebViewDialogOnClickAction(c, dialogTitle, dialogNegativeButton, htmlString, isStringUrl, supportZoom)) - .build(); - } - - - public static MaterialAboutItemOnClickAction createWebsiteOnClickAction(final Context c, final Uri websiteUrl) { - return new MaterialAboutItemOnClickAction() { - @Override - public void onClick() { - Intent i = new Intent(Intent.ACTION_VIEW); - i.setData(websiteUrl); - try { - c.startActivity(i); - } catch (Exception e) { - // No activity to handle intent - Toast.makeText(c, R.string.mal_activity_exception, Toast.LENGTH_SHORT).show(); - } - } - }; - } - - /** - * Creates an ActionItem which will open a url when tapped - * - * @param c context - * @param text - * @param icon - * @param websiteUrl (subText) - * @return Item to add to card. - */ - public static MaterialAboutActionItem createWebsiteActionItem(Context c, Drawable icon, CharSequence text, boolean showAddress, final Uri websiteUrl) { - return new MaterialAboutActionItem.Builder() - .text(text) - .subText((showAddress ? websiteUrl.toString() : null)) - .icon(icon) - .setOnClickAction(createWebsiteOnClickAction(c, websiteUrl)) - .build(); - } - - /** - * Creates a MaterialAboutItemOnClickAction that will open - * the Google Play store listing for the app. - * - * @param c context - * @return onClickAction - */ - public static MaterialAboutItemOnClickAction createRateOnClickAction(final Context c) { - Uri uri = Uri.parse("market://details?id=" + c.getPackageName()); - final Intent goToMarket = new Intent(Intent.ACTION_VIEW, uri); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - goToMarket.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | - Intent.FLAG_ACTIVITY_NEW_DOCUMENT | - Intent.FLAG_ACTIVITY_MULTIPLE_TASK); - } else { - goToMarket.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | - Intent.FLAG_ACTIVITY_MULTIPLE_TASK); - } - - return new MaterialAboutItemOnClickAction() { - @Override - public void onClick() { - try { - c.startActivity(goToMarket); - } catch (ActivityNotFoundException e) { - c.startActivity(new Intent(Intent.ACTION_VIEW, - Uri.parse("http://play.google.com/store/apps/details?id=" + c.getPackageName()))); - } - } - }; - } - - /** - * Creates an ActionItem which will open the play store when tapped - * - * @param c context - * @param text - * @param subText - * @param icon - * @return Item to add to card. - */ - public static MaterialAboutActionItem createRateActionItem(Context c, Drawable icon, CharSequence text, @Nullable CharSequence subText) { - - return new MaterialAboutActionItem.Builder() - .text(text) - .subText(subText) - .icon(icon) - .setOnClickAction(createRateOnClickAction(c)) - .build(); - } - - public static MaterialAboutItemOnClickAction createEmailOnClickAction(final Context c, String email, String emailSubject) { - return createEmailOnClickAction(c, email, emailSubject, c.getString(R.string.mal_send_email)); - } - - /** - * Creates a MaterialAboutItemOnClickAction that will open - * an email intent with specified address. - * - * @param c context - * @param email email address - * @return onClickAction - */ - public static MaterialAboutItemOnClickAction createEmailOnClickAction(final Context c, String email, String emailSubject, final CharSequence chooserTitle) { - - final Intent emailIntent = new Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:" + email)); - emailIntent.putExtra(Intent.EXTRA_SUBJECT, emailSubject); - - return new MaterialAboutItemOnClickAction() { - @Override - public void onClick() { - try { - c.startActivity(Intent.createChooser(emailIntent, chooserTitle)); - } catch (Exception e) { - // No activity to handle intent - Toast.makeText(c, R.string.mal_activity_exception, Toast.LENGTH_SHORT).show(); - } - } - }; - } - - /** - * Creates an ActionItem which will open the an email intent when tapped - * - * @param c context - * @param text - * @param icon - * @param email email address (also used as subText) - * @return Item to add to card. - */ - public static MaterialAboutActionItem createEmailItem(Context c, Drawable icon, CharSequence text, boolean showEmail, String email, String emailSubject, CharSequence chooserTitle) { - return new MaterialAboutActionItem.Builder() - .text(text) - .subText((showEmail ? email : null)) - .icon(icon) - .setOnClickAction(createEmailOnClickAction(c, email, emailSubject, chooserTitle)) - .build(); - } - - public static MaterialAboutActionItem createEmailItem(Context c, Drawable icon, CharSequence text, boolean showEmail, String email, String emailSubject) { - return createEmailItem(c, icon, text, showEmail, email, emailSubject, c.getString(R.string.mal_send_email)); - } - - /** - * Creates a MaterialAboutItemOnClickAction that will open - * the dialer with specified number. - * - * @param c context - * @param number phone number - * @return onClickAction - */ - public static MaterialAboutItemOnClickAction createPhoneOnClickAction(final Context c, String number) { - final Intent phoneIntent = new Intent(Intent.ACTION_DIAL); - phoneIntent.setData(Uri.parse("tel:" + number)); - - return new MaterialAboutItemOnClickAction() { - @Override - public void onClick() { - try { - c.startActivity(phoneIntent); - } catch (Exception e) { - // No activity to handle intent - Toast.makeText(c, R.string.mal_activity_exception, Toast.LENGTH_SHORT).show(); - } - } - }; - } - - /** - * Creates an ActionItem which will open the dialer when tapped - * - * @param c context - * @param text - * @param icon - * @param number phone number (also used as subText) - * @return Item to add to card. - */ - public static MaterialAboutActionItem createPhoneItem(Context c, Drawable icon, CharSequence text, boolean showNumber, String number) { - return new MaterialAboutActionItem.Builder() - .text(text) - .subText((showNumber ? number : null)) - .icon(icon) - .setOnClickAction(createPhoneOnClickAction(c, number)) - .build(); - } - - /** - * Creates a MaterialAboutItemOnClickAction that will open - * maps with a query. - * Query can be either lat,lng(label) or written address - * - * @param c context - * @param addressQuery address query - * @return onClickAction - */ - public static MaterialAboutItemOnClickAction createMapOnClickAction(final Context c, String addressQuery) { - final Intent mapIntent = new Intent(Intent.ACTION_VIEW); - mapIntent.setData(Uri.parse("geo:0,0").buildUpon().appendQueryParameter("q", addressQuery).build()); - return new MaterialAboutItemOnClickAction() { - @Override - public void onClick() { - try { - c.startActivity(mapIntent); - } catch (Exception e) { - // No activity to handle intent - Toast.makeText(c, R.string.mal_activity_exception, Toast.LENGTH_SHORT).show(); - } - } - }; - } - - /** - * Creates an ActionItem which will open maps when tapped - * Query can be either lat,lng(label) or written address - * - * @param c context - * @param text - * @param subText can be set to null - * @param icon - * @param addressQuery addressQuery - * @return Item to add to card. - */ - public static MaterialAboutActionItem createMapItem(Context c, Drawable icon, CharSequence text, CharSequence subText, String addressQuery) { - return new MaterialAboutActionItem.Builder() - .text(text) - .subText(subText) - .icon(icon) - .setOnClickAction(createMapOnClickAction(c, addressQuery)) - .build(); - } - - public static MaterialAboutCard createLicenseCard(Context c, Drawable icon, CharSequence libraryTitle, CharSequence year, CharSequence name, OpenSourceLicense license) { - - MaterialAboutActionItem licenseItem = new MaterialAboutActionItem.Builder() - .icon(icon) - .setIconGravity(MaterialAboutActionItem.GRAVITY_TOP) - .text(libraryTitle) - .subText(String.format(c.getString(license.getResourceId()), year, name)) - .build(); - - return new MaterialAboutCard.Builder().addItem(licenseItem).build(); - } - -} diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/MaterialAboutActivity.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/MaterialAboutActivity.java deleted file mode 100644 index 9a5ec841..00000000 --- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/MaterialAboutActivity.java +++ /dev/null @@ -1,186 +0,0 @@ -package com.danielstone.materialaboutlibrary; - - -import android.content.Context; -import android.os.AsyncTask; -import android.os.Bundle; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import com.google.android.material.appbar.AppBarLayout; -import androidx.interpolator.view.animation.FastOutSlowInInterpolator; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import androidx.recyclerview.widget.SimpleItemAnimator; -import androidx.appcompat.widget.Toolbar; -import android.util.TypedValue; -import android.view.MenuItem; - -import com.danielstone.materialaboutlibrary.adapters.MaterialAboutListAdapter; -import com.danielstone.materialaboutlibrary.model.MaterialAboutList; -import com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager; -import com.danielstone.materialaboutlibrary.util.ViewTypeManager; - -import java.lang.ref.WeakReference; - -public abstract class MaterialAboutActivity extends AppCompatActivity { - - private MaterialAboutList list = new MaterialAboutList.Builder().build(); - private Toolbar toolbar; - private RecyclerView recyclerView; - private MaterialAboutListAdapter adapter; - - @NonNull - protected abstract MaterialAboutList getMaterialAboutList(@NonNull Context context); - - @Nullable - protected abstract CharSequence getActivityTitle(); - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - verifyAttributesExist(); - - setContentView(R.layout.mal_material_about_activity); - - CharSequence title = getActivityTitle(); - if (title == null) - setTitle(R.string.mal_title_about); - else - setTitle(title); - - - assignViews(); - initViews(); - - ListTask task = new ListTask(this); - task.execute(); - } - - private void verifyAttributesExist() { - TypedValue typedValue = new TypedValue(); - boolean malColorPrimaryExists = - getTheme().resolveAttribute(R.attr.mal_color_primary, typedValue, true); - boolean malColorSecondaryExists = - getTheme().resolveAttribute(R.attr.mal_color_secondary, typedValue, true); - if (!malColorPrimaryExists || !malColorSecondaryExists) { - throw new IllegalStateException(String.format("The current theme doesn't provide %s " + - "and/or %s. Please use a theme provided by the library or an extension.", - getResources().getResourceEntryName(R.attr.mal_color_primary), - getResources().getResourceEntryName(R.attr.mal_color_secondary))); - } - } - - private void assignViews() { - toolbar = (Toolbar) findViewById(R.id.mal_toolbar); - recyclerView = (RecyclerView) findViewById(R.id.mal_recyclerview); - recyclerView.setAlpha(0f); - recyclerView.setTranslationY(20); - } - - private void initViews() { - setSupportActionBar(toolbar); - ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setDisplayHomeAsUpEnabled(true); - } - adapter = new MaterialAboutListAdapter(getViewTypeManager()); - recyclerView.setLayoutManager(new LinearLayoutManager(this)); - recyclerView.setAdapter(adapter); - RecyclerView.ItemAnimator animator = recyclerView.getItemAnimator(); - if (animator instanceof SimpleItemAnimator) { - ((SimpleItemAnimator) animator).setSupportsChangeAnimations(false); - } - } - - @NonNull - protected ViewTypeManager getViewTypeManager() { - return new DefaultViewTypeManager(); - } - - @NonNull - protected MaterialAboutList getList() { - return list; - } - - protected boolean shouldAnimate() { - return true; - } - - protected void refreshMaterialAboutList() { - setMaterialAboutList(list); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - onBackPressed(); - return true; - } - return super.onOptionsItemSelected(item); - } - - private void onTaskFinished(@Nullable MaterialAboutList materialAboutList) { - if (materialAboutList != null) { - list = materialAboutList; - adapter.setData(list.getCards()); - - if (shouldAnimate()) { - recyclerView.animate() - .alpha(1f) - .translationY(0f) - .setDuration(600) - .setInterpolator(new FastOutSlowInInterpolator()).start(); - } else { - recyclerView.setAlpha(1f); - recyclerView.setTranslationY(0f); - } - } else { - finish();//?? why we remain here anyway? - } - } - - protected void setMaterialAboutList(MaterialAboutList materialAboutList) { - list = materialAboutList; - adapter.setData(list.getCards()); - } - - protected void setScrollToolbar(boolean scrollToolbar) { - if (toolbar != null) { - AppBarLayout.LayoutParams params = - (AppBarLayout.LayoutParams) toolbar.getLayoutParams(); - if (scrollToolbar) { - params.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL - | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS); - } else { - params.setScrollFlags(0); - } - } - } - - private static class ListTask extends AsyncTask { - - private WeakReference context; - - ListTask(MaterialAboutActivity context) { - this.context = new WeakReference<>(context); - } - - @Override - protected MaterialAboutList doInBackground(String... params) { - return isCancelled() || context.get() == null ? null : context.get().getMaterialAboutList(context.get()); - } - - @Override - protected void onPostExecute(MaterialAboutList materialAboutList) { - super.onPostExecute(materialAboutList); - if (context.get() != null) { - if (!context.get().isFinishing()) { - context.get().onTaskFinished(materialAboutList); - } - } - context = null; - } - } -} diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/MaterialAboutFragment.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/MaterialAboutFragment.java deleted file mode 100644 index c3ad1f04..00000000 --- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/MaterialAboutFragment.java +++ /dev/null @@ -1,132 +0,0 @@ -package com.danielstone.materialaboutlibrary; - -import android.content.Context; -import android.os.AsyncTask; -import android.os.Bundle; - -import androidx.annotation.Nullable; -import androidx.fragment.app.Fragment; -import androidx.interpolator.view.animation.FastOutSlowInInterpolator; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import androidx.recyclerview.widget.SimpleItemAnimator; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import com.danielstone.materialaboutlibrary.adapters.MaterialAboutListAdapter; -import com.danielstone.materialaboutlibrary.model.MaterialAboutList; -import com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager; -import com.danielstone.materialaboutlibrary.util.ViewTypeManager; - -public abstract class MaterialAboutFragment extends Fragment { - - private MaterialAboutList list = new MaterialAboutList.Builder().build(); - private RecyclerView recyclerView; - private MaterialAboutListAdapter adapter; - - public static MaterialAboutFragment newInstance(MaterialAboutFragment fragment) { - return fragment; - } - - protected abstract MaterialAboutList getMaterialAboutList(Context activityContext); - - protected int getTheme() { - return R.style.Theme_Mal_Light; - } - - protected boolean shouldAnimate() { - return true; - } - - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - int style = getTheme(); - - // create ContextThemeWrapper from the original Activity Context with the custom theme - final Context contextThemeWrapper = new android.view.ContextThemeWrapper(getActivity(), style); - LayoutInflater localInflater = inflater.cloneInContext(contextThemeWrapper); - View rootView = localInflater.inflate(R.layout.mal_material_about_fragment, container, false); - - recyclerView = (RecyclerView) rootView.findViewById(R.id.mal_recyclerview); - adapter = new MaterialAboutListAdapter(getViewTypeManager()); - recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); - recyclerView.setAdapter(adapter); - - RecyclerView.ItemAnimator animator = recyclerView.getItemAnimator(); - if (animator instanceof SimpleItemAnimator) { - ((SimpleItemAnimator) animator).setSupportsChangeAnimations(false); - } - - recyclerView.setAlpha(0f); - recyclerView.setTranslationY(20); - - ListTask task = new ListTask(getActivity()); - task.execute(); - - return rootView; - } - - protected ViewTypeManager getViewTypeManager() { - return new DefaultViewTypeManager(); - } - - protected MaterialAboutList getList() { - return list; - } - - protected void setMaterialAboutList(MaterialAboutList materialAboutList) { - //recyclerView.stopScroll(); - //recyclerView.getRecycledViewPool().clear(); - list = materialAboutList; - adapter.setData(list.getCards()); - } - - @Override - public void onPause() { - super.onPause(); - } - - protected void refreshMaterialAboutList() { - setMaterialAboutList(list); - } - - private class ListTask extends AsyncTask { - - Context fragmentContext; - - public ListTask(Context activityContext) { - this.fragmentContext = activityContext; - } - - @Override - protected String doInBackground(String... params) { - list = getMaterialAboutList(fragmentContext); - return null; - } - - @Override - protected void onPostExecute(String s) { - if (list == null) - return;// TODO: 2019-05-09 dirty fix tbh - adapter.setData(list.getCards()); - - if (shouldAnimate()) { - recyclerView.animate() - .alpha(1f) - .translationY(0f) - .setDuration(600) - .setInterpolator(new FastOutSlowInInterpolator()) - .start(); - } else { - recyclerView.setAlpha(1f); - recyclerView.setTranslationY(0f); - } - - super.onPostExecute(s); - fragmentContext = null; - } - } -} diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/adapters/MaterialAboutItemAdapter.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/adapters/MaterialAboutItemAdapter.java deleted file mode 100644 index a3cd1e47..00000000 --- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/adapters/MaterialAboutItemAdapter.java +++ /dev/null @@ -1,167 +0,0 @@ -package com.danielstone.materialaboutlibrary.adapters; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.recyclerview.widget.AsyncListDiffer; -import androidx.recyclerview.widget.DiffUtil; -import androidx.recyclerview.widget.RecyclerView; - -import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder; -import com.danielstone.materialaboutlibrary.items.MaterialAboutItem; -import com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager; -import com.danielstone.materialaboutlibrary.util.ViewTypeManager; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -public class MaterialAboutItemAdapter extends RecyclerView.Adapter { - - private final AsyncListDiffer differ = new AsyncListDiffer(this, DIFF_CALLBACK); - - private ViewTypeManager viewTypeManager; - - private Context context; - - private List data = new ArrayList<>(); - private List oldData = new ArrayList<>(); - - MaterialAboutItemAdapter() { - setHasStableIds(true); - this.viewTypeManager = new DefaultViewTypeManager(); - } - - MaterialAboutItemAdapter(ViewTypeManager customViewTypeManager) { - //Log.d("MaterialItem", "Created adapter"); - setHasStableIds(true); - this.viewTypeManager = customViewTypeManager; - } - - @NonNull - @Override - public MaterialAboutItemViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) { - context = viewGroup.getContext(); - if (!(viewGroup instanceof RecyclerView)) { - throw new RuntimeException("Not bound to RecyclerView"); - } - - int layoutId = viewTypeManager.getLayout(viewType); - - View view = LayoutInflater.from(viewGroup.getContext()).inflate(layoutId, viewGroup, false); - view.setFocusable(true); - - return viewTypeManager.getViewHolder(viewType, view); - } - - @Override - public void onBindViewHolder(MaterialAboutItemViewHolder holder, int position) { - /*if (data.get(position) instanceof MaterialAboutSwitchItem) { - Log.d("MaterialAdapter", "Item "+((MaterialAboutSwitchItem) data.get(position)).getText()+" checked "+((MaterialAboutSwitchItem) data.get(position)).getChecked()); - }*/ - //Log.d("MaterialItem", "Binding "+data.get(position).getDetailString()); - viewTypeManager.setupItem(getItemViewType(position), holder, data.get(position), context); - } - - - @Override - public long getItemId(int position) { - return UUID.fromString(data.get(position).getId()).getMostSignificantBits() & Long.MAX_VALUE; - } - - @Override - public int getItemCount() { - return data.size(); - } - - @Override - public int getItemViewType(int position) { - return data.get(position).getType(); - } - - public void setData(ArrayList data) { - this.data = data; - - notifyDataSetChanged(); - // diff this with previous data - /*DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new MyDiffCallback(oldData, data)); - try { - diffResult.dispatchUpdatesTo(this); - } - catch (IllegalStateException e) { - e.printStackTrace(); - } - - // clone the new data to make further diffs - oldData = new ArrayList<>(); - for (MaterialAboutItem item : data) { - oldData.add(item.clone()); - }*/ - - /*List newData = new ArrayList<>(); - for (MaterialAboutItem item : data) { - newData.add(item.clone()); - } - differ.submitList(newData);*/ - } - - public List getData() { - return data; - } - - - public static final DiffUtil.ItemCallback DIFF_CALLBACK = new DiffUtil.ItemCallback() { - @Override - public boolean areItemsTheSame(MaterialAboutItem oldItem, MaterialAboutItem newItem) { - return oldItem.getId().equals(newItem.getId()); - } - - @Override - public boolean areContentsTheSame(MaterialAboutItem oldItem, MaterialAboutItem newItem) { - return oldItem.getDetailString().equals(newItem.getDetailString()); - } - }; - - public class MyDiffCallback extends DiffUtil.Callback{ - - List oldPersons; - List newPersons; - - public MyDiffCallback(List newPersons, List oldPersons) { - this.newPersons = newPersons; - this.oldPersons = oldPersons; - } - - @Override - public int getOldListSize() { - return oldPersons.size(); - } - - @Override - public int getNewListSize() { - return newPersons.size(); - } - - @Override - public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { - return oldPersons.get(oldItemPosition).getId().equals(newPersons.get(newItemPosition).getId()); - } - - @Override - public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { - return oldPersons.get(oldItemPosition).getDetailString().equals(newPersons.get(newItemPosition).getDetailString()); - } - - @Nullable - @Override - public Object getChangePayload(int oldItemPosition, int newItemPosition) { - //you can return particular field for changed item. - return super.getChangePayload(oldItemPosition, newItemPosition); - } - } - -} diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/adapters/MaterialAboutListAdapter.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/adapters/MaterialAboutListAdapter.java deleted file mode 100644 index e795ee31..00000000 --- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/adapters/MaterialAboutListAdapter.java +++ /dev/null @@ -1,237 +0,0 @@ -package com.danielstone.materialaboutlibrary.adapters; - -import android.content.Context; - -import androidx.annotation.Nullable; -import androidx.recyclerview.widget.AsyncListDiffer; -import androidx.recyclerview.widget.DiffUtil; -import androidx.cardview.widget.CardView; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import com.danielstone.materialaboutlibrary.R; -import com.danielstone.materialaboutlibrary.model.MaterialAboutCard; -import com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager; -import com.danielstone.materialaboutlibrary.util.ViewTypeManager; -import com.google.android.material.card.MaterialCardView; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -public class MaterialAboutListAdapter extends RecyclerView.Adapter { - - private final AsyncListDiffer differ = new AsyncListDiffer(this, DIFF_CALLBACK); - - private ViewTypeManager viewTypeManager; - - private Context context; - - private List data = new ArrayList<>(); - private List oldData = new ArrayList<>(); - - public MaterialAboutListAdapter() { - setHasStableIds(true); - this.viewTypeManager = new DefaultViewTypeManager(); - } - - public MaterialAboutListAdapter(ViewTypeManager customViewTypeManager) { - //Log.d("MaterialList", "Created list adapter"); - setHasStableIds(true); - this.viewTypeManager = customViewTypeManager; - } - - @Override - public MaterialAboutListViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { - context = viewGroup.getContext(); - if (viewGroup instanceof RecyclerView) { - View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.mal_material_about_list_card, viewGroup, false); - view.setFocusable(true); - return new MaterialAboutListViewHolder(view); - } else { - throw new RuntimeException("Not bound to RecyclerView"); - } - } - - @Override - public void onBindViewHolder(MaterialAboutListViewHolder holder, int position) { - MaterialAboutCard card = data.get(position); - - if (holder.cardView instanceof CardView) { - CardView cardView = (CardView) holder.cardView; - int cardColor = card.getCardColor(); - if (cardColor != 0) { - cardView.setCardBackgroundColor(cardColor); - } - } - - CharSequence title = card.getTitle(); - int titleRes = card.getTitleRes(); - - holder.title.setVisibility(View.VISIBLE); - if (title != null) { - holder.title.setText(title); - } else if (titleRes != 0) { - holder.title.setText(titleRes); - } else { - holder.title.setVisibility(View.GONE); - } - - int titleColor = card.getTitleColor(); - - if (holder.title.getVisibility() == View.VISIBLE) { - if (titleColor != 0) { - holder.title.setTextColor(titleColor); - } else { - holder.title.setTextColor(holder.title.getTextColors().getDefaultColor()); - } - } - - if (card.getCustomAdapter() != null) { - holder.useCustomAdapter(card.getCustomAdapter()); - } else { - holder.useMaterialAboutItemAdapter(); - ((MaterialAboutItemAdapter) holder.adapter).setData(card.getItems()); - } - } - - @Override - public long getItemId(int position) { - return UUID.fromString(data.get(position).getId()).getMostSignificantBits() & Long.MAX_VALUE; - } - - @Override - public int getItemCount() { - return data.size(); - } - - public void setData(ArrayList data) { - this.data = data; - - notifyDataSetChanged(); - - /*// diff this with previous data - DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new MyDiffCallback(oldData, data)); - try { - diffResult.dispatchUpdatesTo(this); - } - catch (IllegalStateException e) { - e.printStackTrace(); - } - - // clone the new data to make further diffs - oldData = new ArrayList<>(); - for (MaterialAboutCard card : data) { - oldData.add(card.clone()); - }*/ - //differ.submitList(newData); - } - - - List getData() { - return data; - } - - class MaterialAboutListViewHolder extends RecyclerView.ViewHolder { - - final View cardView; - final TextView title; - final RecyclerView recyclerView; - RecyclerView.Adapter adapter; - - MaterialAboutListViewHolder(View view) { - super(view); - cardView = view.findViewById(R.id.mal_list_card); - title = (TextView) view.findViewById(R.id.mal_list_card_title); - recyclerView = (RecyclerView) view.findViewById(R.id.mal_card_recyclerview); - adapter = new MaterialAboutItemAdapter(viewTypeManager); - recyclerView.setLayoutManager(new LinearLayoutManager(context)); - recyclerView.setAdapter(adapter); - recyclerView.setNestedScrollingEnabled(false); - } - - public void useMaterialAboutItemAdapter() { - if (!(adapter instanceof MaterialAboutItemAdapter)) { - adapter = new MaterialAboutItemAdapter(viewTypeManager); - recyclerView.setLayoutManager(new LinearLayoutManager(context)); - recyclerView.setAdapter(adapter); - } - } - - public void useCustomAdapter(RecyclerView.Adapter newAdapter) { - if (adapter instanceof MaterialAboutItemAdapter) { - recyclerView.setLayoutManager(new LinearLayoutManager(context)); - recyclerView.setAdapter(newAdapter); - } - } - } - - - public static final DiffUtil.ItemCallback DIFF_CALLBACK = new DiffUtil.ItemCallback() { - @Override - public boolean areItemsTheSame(MaterialAboutCard oldItem, MaterialAboutCard newItem) { - return oldItem.getId().equals(newItem.getId()); - } - - @Override - public boolean areContentsTheSame(MaterialAboutCard oldCard, MaterialAboutCard newCard) { - boolean result; - result = oldCard.toString().equals(newCard.toString()); - if (oldCard.getItems().size() != newCard.getItems().size()) return false; - for (int i = 0; i < oldCard.getItems().size(); i++) { - if (!oldCard.getItems().get(i).getDetailString().equals(newCard.getItems().get(i).getDetailString())) return false; - } - return result; - } - }; - - public class MyDiffCallback extends DiffUtil.Callback{ - - List oldPersons; - List newPersons; - - public MyDiffCallback(List newPersons, List oldPersons) { - this.newPersons = newPersons; - this.oldPersons = oldPersons; - } - - @Override - public int getOldListSize() { - return oldPersons.size(); - } - - @Override - public int getNewListSize() { - return newPersons.size(); - } - - @Override - public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { - return oldPersons.get(oldItemPosition).getId().equals(newPersons.get(newItemPosition).getId()); - } - - @Override - public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { - boolean result; - result = oldPersons.get(oldItemPosition).toString().equals(newPersons.get(newItemPosition).toString()); - if (oldPersons.get(oldItemPosition).getItems().size() != newPersons.get(newItemPosition).getItems().size()) return false; - for (int i = 0; i < oldPersons.get(oldItemPosition).getItems().size(); i++) { - if (!oldPersons.get(oldItemPosition).getItems().get(i).getDetailString().equals(newPersons.get(newItemPosition).getItems().get(i).getDetailString())) return false; - } - return result; - } - - @Nullable - @Override - public Object getChangePayload(int oldItemPosition, int newItemPosition) { - //you can return particular field for changed item. - return super.getChangePayload(oldItemPosition, newItemPosition); - } - } -} diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/holders/MaterialAboutItemViewHolder.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/holders/MaterialAboutItemViewHolder.java deleted file mode 100644 index 6188817b..00000000 --- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/holders/MaterialAboutItemViewHolder.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.danielstone.materialaboutlibrary.holders; - -import androidx.recyclerview.widget.RecyclerView; -import android.view.View; - -public abstract class MaterialAboutItemViewHolder extends RecyclerView.ViewHolder { - - public MaterialAboutItemViewHolder(View itemView) { - super(itemView); - } - -} diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutActionItem.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutActionItem.java deleted file mode 100644 index c69f106d..00000000 --- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutActionItem.java +++ /dev/null @@ -1,488 +0,0 @@ -package com.danielstone.materialaboutlibrary.items; - -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.os.Build; - -import androidx.annotation.ColorInt; -import androidx.annotation.DrawableRes; -import androidx.annotation.IntDef; -import androidx.annotation.StringRes; -import android.text.Html; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.View; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.danielstone.materialaboutlibrary.R; -import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder; -import com.danielstone.materialaboutlibrary.util.ViewTypeManager; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import static android.view.View.GONE; - -public class MaterialAboutActionItem extends MaterialAboutItem { - - public static final int GRAVITY_TOP = 0; - public static final int GRAVITY_MIDDLE = 1; - public static final int GRAVITY_BOTTOM = 2; - private CharSequence text = null; - private int textRes = 0; - private CharSequence subText = null; - private int subTextRes = 0; - private int textColor = -1; - private int subTextColor = -1; - private Drawable icon = null; - private int iconRes = 0; - private boolean showIcon = true; - private int iconGravity = GRAVITY_MIDDLE; - private MaterialAboutItemOnClickAction onClickAction = null; - private MaterialAboutItemOnClickAction onLongClickAction = null; - - private MaterialAboutActionItem(Builder builder) { - super(); - this.text = builder.text; - this.textRes = builder.textRes; - - this.subText = builder.subText; - this.subTextRes = builder.subTextRes; - - this.textColor = builder.textColor; - this.subTextColor = builder.subTextColor; - - this.icon = builder.icon; - this.iconRes = builder.iconRes; - - this.showIcon = builder.showIcon; - - this.iconGravity = builder.iconGravity; - - this.onClickAction = builder.onClickAction; - this.onLongClickAction = builder.onLongClickAction; - } - - public MaterialAboutActionItem(CharSequence text, CharSequence subText, Drawable icon, MaterialAboutItemOnClickAction onClickAction) { - this.text = text; - this.subText = subText; - this.icon = icon; - this.onClickAction = onClickAction; - } - - public MaterialAboutActionItem(CharSequence text, CharSequence subText, Drawable icon) { - this.text = text; - this.subText = subText; - this.icon = icon; - } - - public MaterialAboutActionItem(int textRes, int subTextRes, int iconRes, MaterialAboutItemOnClickAction onClickAction) { - this.textRes = textRes; - this.subTextRes = subTextRes; - this.iconRes = iconRes; - this.onClickAction = onClickAction; - } - - public MaterialAboutActionItem(int textRes, int subTextRes, int iconRes) { - this.textRes = textRes; - this.subTextRes = subTextRes; - this.iconRes = iconRes; - } - - public static MaterialAboutItemViewHolder getViewHolder(View view) { - return new MaterialAboutActionItemViewHolder(view); - } - - public static void setupItem(MaterialAboutActionItemViewHolder holder, MaterialAboutActionItem item, Context context) { - CharSequence text = item.getText(); - int textRes = item.getTextRes(); - - holder.text.setVisibility(View.VISIBLE); - if (text != null) { - holder.text.setText(text); - } else if (textRes != 0) { - holder.text.setText(textRes); - } else { - holder.text.setVisibility(GONE); - } - - CharSequence subText = item.getSubText(); - int subTextRes = item.getSubTextRes(); - - holder.subText.setVisibility(View.VISIBLE); - if (subText != null) { - holder.subText.setText(subText); - } else if (subTextRes != 0) { - holder.subText.setText(subTextRes); - } else { - holder.subText.setVisibility(GONE); - } - - if (item.getTextColor() != -1) { - holder.text.setTextColor(item.getTextColor()); - } - if (item.getSubTextColor() != -1) { - holder.subText.setTextColor(item.getSubTextColor()); - } - - if (item.shouldShowIcon()) { - holder.icon.setVisibility(View.VISIBLE); - Drawable drawable = item.getIcon(); - int drawableRes = item.getIconRes(); - if (drawable != null) { - holder.icon.setImageDrawable(drawable); - } else if (drawableRes != 0) { - holder.icon.setImageResource(drawableRes); - } - } else { - holder.icon.setVisibility(GONE); - } - - LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) holder.icon.getLayoutParams(); - switch (item.getIconGravity()) { - case MaterialAboutActionItem.GRAVITY_TOP: - params.gravity = Gravity.TOP; - break; - case MaterialAboutActionItem.GRAVITY_MIDDLE: - params.gravity = Gravity.CENTER_VERTICAL; - break; - case MaterialAboutActionItem.GRAVITY_BOTTOM: - params.gravity = Gravity.BOTTOM; - break; - } - holder.icon.setLayoutParams(params); - - int pL = 0, pT = 0, pR = 0, pB = 0; - if (Build.VERSION.SDK_INT < 21) { - pL = holder.view.getPaddingLeft(); - pT = holder.view.getPaddingTop(); - pR = holder.view.getPaddingRight(); - pB = holder.view.getPaddingBottom(); - } - - if (item.getOnClickAction() != null || item.getOnLongClickAction() != null) { - TypedValue outValue = new TypedValue(); - context.getTheme().resolveAttribute(R.attr.selectableItemBackground, outValue, true); - holder.view.setBackgroundResource(outValue.resourceId); - } else { - holder.view.setBackgroundResource(0); - } - holder.setOnClickAction(item.getOnClickAction()); - holder.setOnLongClickAction(item.getOnLongClickAction()); - - if (Build.VERSION.SDK_INT < 21) { - holder.view.setPadding(pL, pT, pR, pB); - } - } - - @Override - public int getType() { - return ViewTypeManager.ItemType.ACTION_ITEM; - } - - @Override - public String getDetailString() { - return "MaterialAboutActionItem{" + - "text=" + text + - ", textRes=" + textRes + - ", subText=" + subText + - ", subTextRes=" + subTextRes + - ", textColor=" + textColor + - ", descColor=" + subTextColor + - ", icon=" + icon + - ", iconRes=" + iconRes + - ", showIcon=" + showIcon + - ", iconGravity=" + iconGravity + - ", onClickAction=" + onClickAction + - ", onLongClickAction=" + onLongClickAction + - '}'; - } - - public MaterialAboutActionItem(MaterialAboutActionItem item) { - this.id = item.getId(); - this.text = item.getText(); - this.textRes = item.getTextRes(); - this.subText = item.getSubText(); - this.subTextRes = item.getSubTextRes(); - this.textColor = item.getTextColor(); - this.subTextColor = item.getSubTextColor(); - this.icon = item.getIcon(); - this.iconRes = item.getIconRes(); - this.showIcon = item.showIcon; - this.iconGravity = item.iconGravity; - this.onClickAction = item.onClickAction; - this.onLongClickAction = item.onLongClickAction; - } - - @Override - public MaterialAboutItem clone() { - return new MaterialAboutActionItem(this); - } - - public CharSequence getText() { - return text; - } - public MaterialAboutActionItem setText(CharSequence text) { - this.textRes = 0; - this.text = text; - return this; - } - - public int getTextRes() { - return textRes; - } - - public MaterialAboutActionItem setTextRes(int textRes) { - this.text = null; - this.textRes = textRes; - return this; - } - - public CharSequence getSubText() { - return subText; - } - - public MaterialAboutActionItem setSubText(CharSequence subText) { - this.subTextRes = 0; - this.subText = subText; - return this; - } - - public int getSubTextRes() { - return subTextRes; - } - - public MaterialAboutActionItem setSubTextRes(int subTextRes) { - this.subText = null; - this.subTextRes = subTextRes; - return this; - } - - public int getTextColor() { - return textColor; - } - - public MaterialAboutActionItem setTextColor(int textColor) { - this.textColor = textColor; - return this; - } - - public int getSubTextColor() { - return subTextColor; - } - - public MaterialAboutActionItem setSubTextColor(int subTextColor) { - this.subTextColor = subTextColor; - return this; - } - - public Drawable getIcon() { - return icon; - } - - public MaterialAboutActionItem setIcon(Drawable icon) { - this.iconRes = 0; - this.icon = icon; - return this; - } - - public int getIconRes() { - return iconRes; - } - - public MaterialAboutActionItem setIconRes(int iconRes) { - this.icon = null; - this.iconRes = iconRes; - return this; - } - - public boolean shouldShowIcon() { - return showIcon; - } - - public MaterialAboutActionItem setShouldShowIcon(boolean showIcon) { - this.showIcon = showIcon; - return this; - } - - @IconGravity - public int getIconGravity() { - return iconGravity; - } - - public MaterialAboutActionItem setIconGravity(int iconGravity) { - this.iconGravity = iconGravity; - return this; - } - - public MaterialAboutItemOnClickAction getOnClickAction() { - return onClickAction; - } - - public MaterialAboutActionItem setOnClickAction(MaterialAboutItemOnClickAction onClickAction) { - this.onClickAction = onClickAction; - return this; - } - - public MaterialAboutItemOnClickAction getOnLongClickAction() { - return onLongClickAction; - } - - public MaterialAboutActionItem setOnLongClickAction(MaterialAboutItemOnClickAction onLongClickAction) { - this.onLongClickAction = onLongClickAction; - return this; - } - - @Retention(RetentionPolicy.SOURCE) - @IntDef({GRAVITY_TOP, GRAVITY_MIDDLE, GRAVITY_BOTTOM}) - public @interface IconGravity { - } - - public static class MaterialAboutActionItemViewHolder extends MaterialAboutItemViewHolder implements View.OnClickListener, View.OnLongClickListener { - public final View view; - public final ImageView icon; - public final TextView text; - public final TextView subText; - private MaterialAboutItemOnClickAction onClickAction; - private MaterialAboutItemOnClickAction onLongClickAction; - - MaterialAboutActionItemViewHolder(View view) { - super(view); - this.view = view; - icon = (ImageView) view.findViewById(R.id.mal_item_image); - text = (TextView) view.findViewById(R.id.mal_item_text); - subText = (TextView) view.findViewById(R.id.mal_action_item_subtext); - } - - public void setOnClickAction(MaterialAboutItemOnClickAction onClickAction) { - this.onClickAction = onClickAction; - view.setOnClickListener(onClickAction != null ? this : null); - } - - public void setOnLongClickAction(MaterialAboutItemOnClickAction onLongClickAction) { - this.onLongClickAction = onLongClickAction; - view.setOnLongClickListener(onLongClickAction != null ? this : null); - } - - @Override - public void onClick(View v) { - if (onClickAction != null) { - onClickAction.onClick(); - } - } - - @Override - public boolean onLongClick(View v) { - if (onLongClickAction != null) { - onLongClickAction.onClick(); - return true; - } - return false; - } - } - - public static class Builder { - - MaterialAboutItemOnClickAction onClickAction = null; - MaterialAboutItemOnClickAction onLongClickAction = null; - private CharSequence text = null; - @StringRes - private int textRes = 0; - private CharSequence subText = null; - @StringRes - private int subTextRes = 0; - @ColorInt - private int textColor = -1; - @ColorInt - private int subTextColor = -1; - private Drawable icon = null; - @DrawableRes - private int iconRes = 0; - private boolean showIcon = true; - @IconGravity - private int iconGravity = GRAVITY_MIDDLE; - - public Builder text(CharSequence text) { - this.text = text; - this.textRes = 0; - return this; - } - - public Builder text(@StringRes int text) { - this.textRes = text; - this.text = null; - return this; - } - - public Builder subText(CharSequence subText) { - this.subText = subText; - this.subTextRes = 0; - return this; - } - - public Builder subText(@StringRes int subTextRes) { - this.subText = null; - this.subTextRes = subTextRes; - return this; - } - - public Builder textColor(@ColorInt int textColor) { - this.textColor = textColor; - return this; - } - - public Builder subTextColor(@ColorInt int subTextColor) { - this.subTextColor = subTextColor; - return this; - } - - public Builder subTextHtml(String subTextHtml) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - this.subText = Html.fromHtml(subTextHtml, Html.FROM_HTML_MODE_LEGACY); - } else { - //noinspection deprecation - this.subText = Html.fromHtml(subTextHtml); - } - this.subTextRes = 0; - return this; - } - - public Builder icon(Drawable icon) { - this.icon = icon; - this.iconRes = 0; - return this; - } - - public Builder icon(@DrawableRes int iconRes) { - this.icon = null; - this.iconRes = iconRes; - return this; - } - - public Builder showIcon(boolean showIcon) { - this.showIcon = showIcon; - return this; - } - - public Builder setIconGravity(@IconGravity int iconGravity) { - this.iconGravity = iconGravity; - return this; - } - - public Builder setOnClickAction(MaterialAboutItemOnClickAction onClickAction) { - this.onClickAction = onClickAction; - return this; - } - - public Builder setOnLongClickAction(MaterialAboutItemOnClickAction onLongClickAction) { - this.onLongClickAction = onLongClickAction; - return this; - } - - public MaterialAboutActionItem build() { - return new MaterialAboutActionItem(this); - } - } -} diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutActionSwitchItem.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutActionSwitchItem.java deleted file mode 100644 index eb6d9411..00000000 --- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutActionSwitchItem.java +++ /dev/null @@ -1,606 +0,0 @@ -package com.danielstone.materialaboutlibrary.items; - -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.os.Build; -import androidx.annotation.DrawableRes; -import androidx.annotation.IntDef; -import androidx.annotation.StringRes; -import androidx.appcompat.widget.SwitchCompat; - -import android.text.Html; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.View; -import android.widget.CompoundButton; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.Switch; -import android.widget.TextView; - -import com.danielstone.materialaboutlibrary.R; -import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder; -import com.danielstone.materialaboutlibrary.util.ViewTypeManager; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import static android.view.View.GONE; - -public class MaterialAboutActionSwitchItem extends MaterialAboutItem { - - public static final int GRAVITY_TOP = 0; - public static final int GRAVITY_MIDDLE = 1; - public static final int GRAVITY_BOTTOM = 2; - private CharSequence text = null; - private int textRes = 0; - private CharSequence subText = null; - private int subTextRes = 0; - private CharSequence subTextChecked = null; - private int subTextCheckedRes = 0; - private Drawable icon = null; - private int iconRes = 0; - private boolean showIcon = true; - private int iconGravity = GRAVITY_MIDDLE; - private boolean checked = false; - private int tag = -1; - private MaterialAboutItemOnClickAction onClickAction = null; - private MaterialAboutItemOnClickAction onLongClickAction = null; - private MaterialAboutItemOnChangeAction onChangeAction = null; - - private MaterialAboutActionSwitchItem(Builder builder) { - super(); - this.text = builder.text; - this.textRes = builder.textRes; - - this.subText = builder.subText; - this.subTextRes = builder.subTextRes; - - this.subTextChecked = builder.subTextChecked; - this.subTextCheckedRes = builder.subTextCheckedRes; - - this.icon = builder.icon; - this.iconRes = builder.iconRes; - - this.showIcon = builder.showIcon; - - this.iconGravity = builder.iconGravity; - - this.checked = builder.checked; - - this.tag = builder.tag; - - this.onClickAction = builder.onClickAction; - this.onLongClickAction = builder.onLongClickAction; - this.onChangeAction = builder.onChangeAction; - } - - public MaterialAboutActionSwitchItem(CharSequence text, CharSequence subText, Drawable icon, MaterialAboutItemOnChangeAction onChangeAction) { - this.text = text; - this.subText = subText; - this.icon = icon; - this.onChangeAction = onChangeAction; - } - - public MaterialAboutActionSwitchItem(CharSequence text, CharSequence subText, Drawable icon) { - this.text = text; - this.subText = subText; - this.icon = icon; - } - - public MaterialAboutActionSwitchItem(int textRes, int subTextRes, int iconRes, MaterialAboutItemOnChangeAction onChangeAction) { - this.textRes = textRes; - this.subTextRes = subTextRes; - this.iconRes = iconRes; - this.onChangeAction = onChangeAction; - } - - public MaterialAboutActionSwitchItem(int textRes, int subTextRes, int iconRes) { - this.textRes = textRes; - this.subTextRes = subTextRes; - this.iconRes = iconRes; - } - - public static void setupItem(MaterialAboutActionSwitchItemViewHolder holder, MaterialAboutActionSwitchItem item, Context context) { - holder.switchItem = item; - - CharSequence text = item.getText(); - int textRes = item.getTextRes(); - - holder.text.setVisibility(View.VISIBLE); - if (text != null) { - holder.text.setText(text); - } else if (textRes != 0) { - holder.text.setText(textRes); - } else { - holder.text.setVisibility(GONE); - } - - CharSequence subText = item.getSubText(); - int subTextRes = item.getSubTextRes(); - - holder.subText.setVisibility(View.VISIBLE); - if (subText != null) { - holder.subText.setText(subText); - } else if (subTextRes != 0) { - holder.subText.setText(subTextRes); - } else { - holder.subText.setVisibility(GONE); - } - - if (item.shouldShowIcon()) { - holder.icon.setVisibility(View.VISIBLE); - Drawable drawable = item.getIcon(); - int drawableRes = item.getIconRes(); - if (drawable != null) { - holder.icon.setImageDrawable(drawable); - } else if (drawableRes != 0) { - holder.icon.setImageResource(drawableRes); - } - } else { - holder.icon.setVisibility(GONE); - } - - LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) holder.icon.getLayoutParams(); - switch (item.getIconGravity()) { - case MaterialAboutActionSwitchItem.GRAVITY_TOP: - params.gravity = Gravity.TOP; - break; - case MaterialAboutActionSwitchItem.GRAVITY_MIDDLE: - params.gravity = Gravity.CENTER_VERTICAL; - break; - case MaterialAboutActionSwitchItem.GRAVITY_BOTTOM: - params.gravity = Gravity.BOTTOM; - break; - } - holder.icon.setLayoutParams(params); - - int pL = 0, pT = 0, pR = 0, pB = 0; - if (Build.VERSION.SDK_INT < 21) { - pL = holder.view.getPaddingLeft(); - pT = holder.view.getPaddingTop(); - pR = holder.view.getPaddingRight(); - pB = holder.view.getPaddingBottom(); - } - - holder.setChecked(item.getChecked()); - - if (item.getOnChangeAction() != null || item.getOnClickAction() != null || item.getOnLongClickAction() != null) { - TypedValue outValue = new TypedValue(); - context.getTheme().resolveAttribute(R.attr.selectableItemBackground, outValue, true); - holder.view.setBackgroundResource(outValue.resourceId); - } else { - holder.view.setBackgroundResource(0); - } - holder.setOnClickAction(item.getOnClickAction()); - holder.setOnLongClickAction(item.getOnLongClickAction()); - holder.setOnChangeAction(item.getOnChangeAction()); - - if (Build.VERSION.SDK_INT < 21) { - holder.view.setPadding(pL, pT, pR, pB); - } - } - - public static MaterialAboutItemViewHolder getViewHolder(View view) { - return new MaterialAboutActionSwitchItemViewHolder(view); - } - - public static class MaterialAboutActionSwitchItemViewHolder extends MaterialAboutItemViewHolder implements View.OnClickListener, View.OnLongClickListener, CompoundButton.OnCheckedChangeListener { - public final View view; - public final ImageView icon; - public final TextView text; - public final TextView subText; - public final SwitchCompat switchView; - private MaterialAboutItemOnClickAction onClickAction; - private MaterialAboutItemOnClickAction onLongClickAction; - private MaterialAboutItemOnChangeAction onChangeAction; - private MaterialAboutActionSwitchItem switchItem; - - MaterialAboutActionSwitchItemViewHolder(View view) { - super(view); - this.view = view.findViewById(R.id.mal_action_root); - icon = view.findViewById(R.id.mal_item_image); - text = view.findViewById(R.id.mal_item_text); - subText = view.findViewById(R.id.mal_action_item_subtext); - switchView = view.findViewById(R.id.mal_switch); - } - - public void setOnClickAction(MaterialAboutItemOnClickAction onClickAction) { - this.onClickAction = onClickAction; - view.setOnClickListener(onClickAction != null ? this : null); - } - - public void setOnLongClickAction(MaterialAboutItemOnClickAction onLongClickAction) { - this.onLongClickAction = onLongClickAction; - view.setOnLongClickListener(onLongClickAction != null ? this : null); - } - - public void setOnChangeAction(MaterialAboutItemOnChangeAction onChangeAction) { - this.onChangeAction = onChangeAction; - switchView.setOnCheckedChangeListener(this); - } - - public void setChecked(boolean checked) { - switchView.setChecked(checked); - switchItem.checked = checked; - updateSubText(checked); - } - - public void updateSubText(boolean checked) { - if (checked && switchItem.subTextChecked != null) { - subText.setText(switchItem.subTextChecked); - } - else if (checked && switchItem.subTextCheckedRes != 0) { - subText.setText(switchItem.subTextCheckedRes); - } - else if (switchItem.subText != null) { - subText.setText(switchItem.subText); - } - else if (switchItem.subTextRes != 0) { - subText.setText(switchItem.subTextRes); - } - } - - @Override - public void onClick(View v) { - if (onClickAction != null) { - onClickAction.onClick(); - } - } - - @Override - public boolean onLongClick(View v) { - if (onLongClickAction != null) { - onLongClickAction.onClick(); - return true; - } - return false; - } - - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - updateSubText(isChecked); - if (onChangeAction != null) { - if (!onChangeAction.onChange(isChecked, switchItem.getTag())) { - setChecked(!isChecked); - } - else { - switchItem.checked = isChecked; - } - } - else { - setChecked(!isChecked); - } - } - } - - @Override - public int getType() { - return ViewTypeManager.ItemType.ACTION_SWITCH_ITEM; - } - - @Override - public String getDetailString() { - return "MaterialAboutActionSwitchItem{" + - "text=" + text + - ", textRes=" + textRes + - ", subText=" + subText + - ", subTextRes=" + subTextRes + - ", subTextChecked=" + subTextChecked + - ", subTextCheckedRes=" + subTextCheckedRes + - ", icon=" + icon + - ", iconRes=" + iconRes + - ", showIcon=" + showIcon + - ", iconGravity=" + iconGravity + - ", checked=" + checked + - ", tag=" + tag + - ", onClickAction=" + onClickAction + - ", onLongClickAction=" + onLongClickAction + - ", onChangeAction=" + onChangeAction + - '}'; - } - - public MaterialAboutActionSwitchItem(MaterialAboutActionSwitchItem item) { - this.id = item.getId(); - this.text = item.getText(); - this.textRes = item.getTextRes(); - this.subText = item.getSubText(); - this.subTextRes = item.getSubTextRes(); - this.subTextChecked = item.getSubTextChecked(); - this.subTextCheckedRes = item.getSubTextCheckedRes(); - this.icon = item.getIcon(); - this.iconRes = item.getIconRes(); - this.showIcon = item.showIcon; - this.iconGravity = item.iconGravity; - this.checked = item.checked; - this.tag = item.tag; - this.onClickAction = item.onClickAction; - this.onLongClickAction = item.onLongClickAction; - this.onChangeAction = item.onChangeAction; - } - - @Override - public MaterialAboutItem clone() { - return new MaterialAboutActionSwitchItem(this); - } - - public int getTag() { - return tag; - } - public MaterialAboutActionSwitchItem setTag(int tag) { - this.tag = tag; - return this; - } - - public CharSequence getText() { - return text; - } - public MaterialAboutActionSwitchItem setText(CharSequence text) { - this.textRes = 0; - this.text = text; - return this; - } - - public int getTextRes() { - return textRes; - } - - public MaterialAboutActionSwitchItem setTextRes(int textRes) { - this.text = null; - this.textRes = textRes; - return this; - } - - public CharSequence getSubText() { - return subText; - } - - public MaterialAboutActionSwitchItem setSubText(CharSequence subText) { - this.subTextRes = 0; - this.subText = subText; - return this; - } - - public int getSubTextRes() { - return subTextRes; - } - - public MaterialAboutActionSwitchItem setSubTextRes(int subTextRes) { - this.subText = null; - this.subTextRes = subTextRes; - return this; - } - - public CharSequence getSubTextChecked() { - return subTextChecked; - } - - public MaterialAboutActionSwitchItem setSubTextChecked(CharSequence subTextChecked) { - this.subTextCheckedRes = 0; - this.subTextChecked = subTextChecked; - return this; - } - - public int getSubTextCheckedRes() { - return subTextCheckedRes; - } - - public MaterialAboutActionSwitchItem setSubTextCheckedRes(int subTextCheckedRes) { - this.subTextChecked = null; - this.subTextCheckedRes = subTextCheckedRes; - return this; - } - - public Drawable getIcon() { - return icon; - } - - public MaterialAboutActionSwitchItem setIcon(Drawable icon) { - this.iconRes = 0; - this.icon = icon; - return this; - } - - public int getIconRes() { - return iconRes; - } - - public MaterialAboutActionSwitchItem setIconRes(int iconRes) { - this.icon = null; - this.iconRes = iconRes; - return this; - } - - public boolean shouldShowIcon() { - return showIcon; - } - - public MaterialAboutActionSwitchItem setShouldShowIcon(boolean showIcon) { - this.showIcon = showIcon; - return this; - } - - @IconGravity - public int getIconGravity() { - return iconGravity; - } - - public MaterialAboutActionSwitchItem setIconGravity(int iconGravity) { - this.iconGravity = iconGravity; - return this; - } - - public boolean getChecked() { - return checked; - } - - public MaterialAboutActionSwitchItem setChecked(boolean checked) { - this.checked = checked; - return this; - } - - public MaterialAboutItemOnClickAction getOnClickAction() { - return onClickAction; - } - - public MaterialAboutActionSwitchItem setOnClickAction(MaterialAboutItemOnClickAction onClickAction) { - this.onClickAction = onClickAction; - return this; - } - - public MaterialAboutItemOnClickAction getOnLongClickAction() { - return onLongClickAction; - } - - public MaterialAboutActionSwitchItem setOnLongClickAction(MaterialAboutItemOnClickAction onLongClickAction) { - this.onLongClickAction = onLongClickAction; - return this; - } - - public MaterialAboutItemOnChangeAction getOnChangeAction() { - return onChangeAction; - } - - public MaterialAboutActionSwitchItem setOnChangeAction(MaterialAboutItemOnChangeAction onChangeAction) { - this.onChangeAction = onChangeAction; - return this; - } - - @Retention(RetentionPolicy.SOURCE) - @IntDef({GRAVITY_TOP, GRAVITY_MIDDLE, GRAVITY_BOTTOM}) - public @interface IconGravity { - } - - public static class Builder { - - MaterialAboutItemOnClickAction onClickAction = null; - MaterialAboutItemOnClickAction onLongClickAction = null; - MaterialAboutItemOnChangeAction onChangeAction = null; - private CharSequence text = null; - @StringRes - private int textRes = 0; - private CharSequence subText = null; - @StringRes - private int subTextRes = 0; - private CharSequence subTextChecked = null; - @StringRes - private int subTextCheckedRes = 0; - private Drawable icon = null; - @DrawableRes - private int iconRes = 0; - private boolean showIcon = true; - @IconGravity - private int iconGravity = GRAVITY_MIDDLE; - private boolean checked = false; - private int tag = -1; - - public Builder tag(int tag) { - this.tag = tag; - return this; - } - - public Builder text(CharSequence text) { - this.text = text; - this.textRes = 0; - return this; - } - - public Builder text(@StringRes int text) { - this.textRes = text; - this.text = null; - return this; - } - - public Builder subText(CharSequence subText) { - this.subText = subText; - this.subTextRes = 0; - return this; - } - - public Builder subText(@StringRes int subTextRes) { - this.subText = null; - this.subTextRes = subTextRes; - return this; - } - - public Builder subTextHtml(String subTextHtml) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - this.subText = Html.fromHtml(subTextHtml, Html.FROM_HTML_MODE_LEGACY); - } else { - //noinspection deprecation - this.subText = Html.fromHtml(subTextHtml); - } - this.subTextRes = 0; - return this; - } - - public Builder subTextChecked(CharSequence subTextChecked) { - this.subTextChecked = subTextChecked; - this.subTextCheckedRes = 0; - return this; - } - - public Builder subTextChecked(@StringRes int subTextCheckedRes) { - this.subTextChecked = null; - this.subTextCheckedRes = subTextCheckedRes; - return this; - } - - public Builder subTextCheckedHtml(String subTextCheckedHtml) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - this.subTextChecked = Html.fromHtml(subTextCheckedHtml, Html.FROM_HTML_MODE_LEGACY); - } else { - //noinspection deprecation - this.subTextChecked = Html.fromHtml(subTextCheckedHtml); - } - this.subTextCheckedRes = 0; - return this; - } - - public Builder icon(Drawable icon) { - this.icon = icon; - this.iconRes = 0; - return this; - } - - public Builder icon(@DrawableRes int iconRes) { - this.icon = null; - this.iconRes = iconRes; - return this; - } - - public Builder showIcon(boolean showIcon) { - this.showIcon = showIcon; - return this; - } - - public Builder setIconGravity(@IconGravity int iconGravity) { - this.iconGravity = iconGravity; - return this; - } - - public Builder setOnClickAction(MaterialAboutItemOnClickAction onClickAction) { - this.onClickAction = onClickAction; - return this; - } - - public Builder setOnLongClickAction(MaterialAboutItemOnClickAction onLongClickAction) { - this.onLongClickAction = onLongClickAction; - return this; - } - - public Builder setOnChangeAction(MaterialAboutItemOnChangeAction onChangeAction) { - this.onChangeAction = onChangeAction; - return this; - } - - public Builder checked(boolean isChecked) { - this.checked = isChecked; - return this; - } - - public MaterialAboutActionSwitchItem build() { - return new MaterialAboutActionSwitchItem(this); - } - } -} diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutCheckboxItem.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutCheckboxItem.java deleted file mode 100644 index 16a6cd45..00000000 --- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutCheckboxItem.java +++ /dev/null @@ -1,538 +0,0 @@ -package com.danielstone.materialaboutlibrary.items; - -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.os.Build; -import androidx.annotation.DrawableRes; -import androidx.annotation.IntDef; -import androidx.annotation.StringRes; -import android.text.Html; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.View; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.danielstone.materialaboutlibrary.R; -import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder; -import com.danielstone.materialaboutlibrary.util.ViewTypeManager; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import static android.view.View.GONE; - -public class MaterialAboutCheckboxItem extends MaterialAboutItem { - - public static final int GRAVITY_TOP = 0; - public static final int GRAVITY_MIDDLE = 1; - public static final int GRAVITY_BOTTOM = 2; - private CharSequence text = null; - private int textRes = 0; - private CharSequence subText = null; - private int subTextRes = 0; - private CharSequence subTextChecked = null; - private int subTextCheckedRes = 0; - private Drawable icon = null; - private int iconRes = 0; - private boolean showIcon = true; - private int iconGravity = GRAVITY_MIDDLE; - private boolean checked = false; - private int tag = -1; - private MaterialAboutItemOnChangeAction onChangeAction = null; - - private MaterialAboutCheckboxItem(Builder builder) { - super(); - this.text = builder.text; - this.textRes = builder.textRes; - - this.subText = builder.subText; - this.subTextRes = builder.subTextRes; - - this.subTextChecked = builder.subTextChecked; - this.subTextCheckedRes = builder.subTextCheckedRes; - - this.icon = builder.icon; - this.iconRes = builder.iconRes; - - this.showIcon = builder.showIcon; - - this.iconGravity = builder.iconGravity; - - this.checked = builder.checked; - - this.tag = builder.tag; - - this.onChangeAction = builder.onChangeAction; - } - - public MaterialAboutCheckboxItem(CharSequence text, CharSequence subText, Drawable icon, MaterialAboutItemOnChangeAction onChangeAction) { - this.text = text; - this.subText = subText; - this.icon = icon; - this.onChangeAction = onChangeAction; - } - - public MaterialAboutCheckboxItem(CharSequence text, CharSequence subText, Drawable icon) { - this.text = text; - this.subText = subText; - this.icon = icon; - } - - public MaterialAboutCheckboxItem(int textRes, int subTextRes, int iconRes, MaterialAboutItemOnChangeAction onChangeAction) { - this.textRes = textRes; - this.subTextRes = subTextRes; - this.iconRes = iconRes; - this.onChangeAction = onChangeAction; - } - - public MaterialAboutCheckboxItem(int textRes, int subTextRes, int iconRes) { - this.textRes = textRes; - this.subTextRes = subTextRes; - this.iconRes = iconRes; - } - - public static MaterialAboutItemViewHolder getViewHolder(View view) { - return new MaterialAboutCheckboxItemViewHolder(view); - } - - public static void setupItem(MaterialAboutCheckboxItemViewHolder holder, MaterialAboutCheckboxItem item, Context context) { - holder.switchItem = item; - - CharSequence text = item.getText(); - int textRes = item.getTextRes(); - - holder.text.setVisibility(View.VISIBLE); - if (text != null) { - holder.text.setText(text); - } else if (textRes != 0) { - holder.text.setText(textRes); - } else { - holder.text.setVisibility(GONE); - } - - CharSequence subText = item.getSubText(); - int subTextRes = item.getSubTextRes(); - - holder.subText.setVisibility(View.VISIBLE); - if (subText != null) { - holder.subText.setText(subText); - } else if (subTextRes != 0) { - holder.subText.setText(subTextRes); - } else { - holder.subText.setVisibility(GONE); - } - - if (item.shouldShowIcon()) { - holder.icon.setVisibility(View.VISIBLE); - Drawable drawable = item.getIcon(); - int drawableRes = item.getIconRes(); - if (drawable != null) { - holder.icon.setImageDrawable(drawable); - } else if (drawableRes != 0) { - holder.icon.setImageResource(drawableRes); - } - } else { - holder.icon.setVisibility(GONE); - } - - LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) holder.icon.getLayoutParams(); - switch (item.getIconGravity()) { - case MaterialAboutCheckboxItem.GRAVITY_TOP: - params.gravity = Gravity.TOP; - break; - case MaterialAboutCheckboxItem.GRAVITY_MIDDLE: - params.gravity = Gravity.CENTER_VERTICAL; - break; - case MaterialAboutCheckboxItem.GRAVITY_BOTTOM: - params.gravity = Gravity.BOTTOM; - break; - } - holder.icon.setLayoutParams(params); - - int pL = 0, pT = 0, pR = 0, pB = 0; - if (Build.VERSION.SDK_INT < 21) { - pL = holder.view.getPaddingLeft(); - pT = holder.view.getPaddingTop(); - pR = holder.view.getPaddingRight(); - pB = holder.view.getPaddingBottom(); - } - - - if (item.getOnChangeAction() != null) { - TypedValue outValue = new TypedValue(); - context.getTheme().resolveAttribute(R.attr.selectableItemBackground, outValue, true); - holder.view.setBackgroundResource(outValue.resourceId); - } else { - holder.view.setBackgroundResource(0); - } - holder.setOnChangeAction(item.getOnChangeAction()); - - if (Build.VERSION.SDK_INT < 21) { - holder.view.setPadding(pL, pT, pR, pB); - } - } - - @Override - public int getType() { - return ViewTypeManager.ItemType.CHECKBOX_ITEM; - } - - @Override - public String getDetailString() { - return "MaterialAboutCheckboxItem{" + - "text=" + text + - ", textRes=" + textRes + - ", subText=" + subText + - ", subTextRes=" + subTextRes + - ", subTextChecked=" + subTextChecked + - ", subTextCheckedRes=" + subTextCheckedRes + - ", icon=" + icon + - ", iconRes=" + iconRes + - ", showIcon=" + showIcon + - ", iconGravity=" + iconGravity + - ", checked=" + checked + - ", tag=" + tag + - ", onChangeAction=" + onChangeAction + - '}'; - } - - public MaterialAboutCheckboxItem(MaterialAboutCheckboxItem item) { - this.id = item.getId(); - this.text = item.getText(); - this.textRes = item.getTextRes(); - this.subText = item.getSubText(); - this.subTextRes = item.getSubTextRes(); - this.subTextChecked = item.getSubTextChecked(); - this.subTextCheckedRes = item.getSubTextCheckedRes(); - this.icon = item.getIcon(); - this.iconRes = item.getIconRes(); - this.showIcon = item.showIcon; - this.iconGravity = item.iconGravity; - this.checked = item.checked; - this.tag = item.tag; - this.onChangeAction = item.onChangeAction; - } - - @Override - public MaterialAboutItem clone() { - return new MaterialAboutCheckboxItem(this); - } - - public int getTag() { - return tag; - } - public MaterialAboutCheckboxItem setTag(int tag) { - this.tag = tag; - return this; - } - - public CharSequence getText() { - return text; - } - public MaterialAboutCheckboxItem setText(CharSequence text) { - this.textRes = 0; - this.text = text; - return this; - } - - public int getTextRes() { - return textRes; - } - - public MaterialAboutCheckboxItem setTextRes(int textRes) { - this.text = null; - this.textRes = textRes; - return this; - } - - public CharSequence getSubText() { - return subText; - } - - public MaterialAboutCheckboxItem setSubText(CharSequence subText) { - this.subTextRes = 0; - this.subText = subText; - return this; - } - - public int getSubTextRes() { - return subTextRes; - } - - public MaterialAboutCheckboxItem setSubTextRes(int subTextRes) { - this.subText = null; - this.subTextRes = subTextRes; - return this; - } - - public CharSequence getSubTextChecked() { - return subTextChecked; - } - - public MaterialAboutCheckboxItem setSubTextChecked(CharSequence subTextChecked) { - this.subTextCheckedRes = 0; - this.subTextChecked = subTextChecked; - return this; - } - - public int getSubTextCheckedRes() { - return subTextCheckedRes; - } - - public MaterialAboutCheckboxItem setSubTextCheckedRes(int subTextCheckedRes) { - this.subTextChecked = null; - this.subTextCheckedRes = subTextCheckedRes; - return this; - } - - public Drawable getIcon() { - return icon; - } - - public MaterialAboutCheckboxItem setIcon(Drawable icon) { - this.iconRes = 0; - this.icon = icon; - return this; - } - - public int getIconRes() { - return iconRes; - } - - public MaterialAboutCheckboxItem setIconRes(int iconRes) { - this.icon = null; - this.iconRes = iconRes; - return this; - } - - public boolean shouldShowIcon() { - return showIcon; - } - - public MaterialAboutCheckboxItem setShouldShowIcon(boolean showIcon) { - this.showIcon = showIcon; - return this; - } - - @IconGravity - public int getIconGravity() { - return iconGravity; - } - - public MaterialAboutCheckboxItem setIconGravity(int iconGravity) { - this.iconGravity = iconGravity; - return this; - } - - public boolean getChecked() { - return checked; - } - - public MaterialAboutCheckboxItem setChecked(boolean checked) { - this.checked = checked; - return this; - } - - public MaterialAboutItemOnChangeAction getOnChangeAction() { - return onChangeAction; - } - - public MaterialAboutCheckboxItem setOnChangeAction(MaterialAboutItemOnChangeAction onChangeAction) { - this.onChangeAction = onChangeAction; - return this; - } - - @Retention(RetentionPolicy.SOURCE) - @IntDef({GRAVITY_TOP, GRAVITY_MIDDLE, GRAVITY_BOTTOM}) - public @interface IconGravity { - } - - public static class MaterialAboutCheckboxItemViewHolder extends MaterialAboutItemViewHolder implements View.OnClickListener, CompoundButton.OnCheckedChangeListener { - public final View view; - public final ImageView icon; - public final TextView text; - public final TextView subText; - public final CheckBox checkBox; - private MaterialAboutItemOnChangeAction onChangeAction; - private MaterialAboutCheckboxItem switchItem; - - MaterialAboutCheckboxItemViewHolder(View view) { - super(view); - this.view = view; - icon = view.findViewById(R.id.mal_item_image); - text = view.findViewById(R.id.mal_item_text); - subText = view.findViewById(R.id.mal_action_item_subtext); - checkBox = view.findViewById(R.id.mal_checkbox); - } - - public void setOnChangeAction(MaterialAboutItemOnChangeAction onChangeAction) { - this.onChangeAction = onChangeAction; - view.setOnClickListener(onChangeAction != null ? this : null); - checkBox.setOnCheckedChangeListener(this); - } - - public void setChecked(boolean checked) { - checkBox.setOnCheckedChangeListener(null); - checkBox.setChecked(checked); - checkBox.setOnCheckedChangeListener(this); - updateSubText(checked); - } - - public void updateSubText(boolean checked) { - if (checked && switchItem.subTextChecked != null) { - subText.setText(switchItem.subTextChecked); - } - else if (checked && switchItem.subTextCheckedRes != 0) { - subText.setText(switchItem.subTextCheckedRes); - } - else if (switchItem.subText != null) { - subText.setText(switchItem.subText); - } - else if (switchItem.subTextRes != 0) { - subText.setText(switchItem.subTextRes); - } - } - - @Override - public void onClick(View v) { - checkBox.toggle(); - } - - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - updateSubText(isChecked); - if (onChangeAction != null) { - if (!onChangeAction.onChange(isChecked, switchItem.getTag())) - setChecked(!isChecked); - } - else { - setChecked(!isChecked); - } - } - } - - public static class Builder { - - MaterialAboutItemOnChangeAction onChangeAction = null; - private CharSequence text = null; - @StringRes - private int textRes = 0; - private CharSequence subText = null; - @StringRes - private int subTextRes = 0; - private CharSequence subTextChecked = null; - @StringRes - private int subTextCheckedRes = 0; - private Drawable icon = null; - @DrawableRes - private int iconRes = 0; - private boolean showIcon = true; - @IconGravity - private int iconGravity = GRAVITY_MIDDLE; - private boolean checked = false; - private int tag = -1; - - public Builder tag(int tag) { - this.tag = tag; - return this; - } - - public Builder text(CharSequence text) { - this.text = text; - this.textRes = 0; - return this; - } - - public Builder text(@StringRes int text) { - this.textRes = text; - this.text = null; - return this; - } - - public Builder subText(CharSequence subText) { - this.subText = subText; - this.subTextRes = 0; - return this; - } - - public Builder subText(@StringRes int subTextRes) { - this.subText = null; - this.subTextRes = subTextRes; - return this; - } - - public Builder subTextHtml(String subTextHtml) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - this.subText = Html.fromHtml(subTextHtml, Html.FROM_HTML_MODE_LEGACY); - } else { - //noinspection deprecation - this.subText = Html.fromHtml(subTextHtml); - } - this.subTextRes = 0; - return this; - } - - public Builder subTextChecked(CharSequence subTextChecked) { - this.subTextChecked = subTextChecked; - this.subTextCheckedRes = 0; - return this; - } - - public Builder subTextChecked(@StringRes int subTextCheckedRes) { - this.subTextChecked = null; - this.subTextCheckedRes = subTextCheckedRes; - return this; - } - - public Builder subTextCheckedHtml(String subTextCheckedHtml) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - this.subTextChecked = Html.fromHtml(subTextCheckedHtml, Html.FROM_HTML_MODE_LEGACY); - } else { - //noinspection deprecation - this.subTextChecked = Html.fromHtml(subTextCheckedHtml); - } - this.subTextCheckedRes = 0; - return this; - } - - public Builder icon(Drawable icon) { - this.icon = icon; - this.iconRes = 0; - return this; - } - - public Builder icon(@DrawableRes int iconRes) { - this.icon = null; - this.iconRes = iconRes; - return this; - } - - public Builder showIcon(boolean showIcon) { - this.showIcon = showIcon; - return this; - } - - public Builder setIconGravity(@IconGravity int iconGravity) { - this.iconGravity = iconGravity; - return this; - } - - public Builder setOnChangeAction(MaterialAboutItemOnChangeAction onChangeAction) { - this.onChangeAction = onChangeAction; - return this; - } - - public Builder checked(boolean isChecked) { - this.checked = isChecked; - return this; - } - - public MaterialAboutCheckboxItem build() { - return new MaterialAboutCheckboxItem(this); - } - } -} diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutItem.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutItem.java deleted file mode 100644 index 2d6a5f48..00000000 --- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutItem.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.danielstone.materialaboutlibrary.items; - -import java.util.UUID; - -public abstract class MaterialAboutItem { - - public String id = "NO-UUID"; - - public MaterialAboutItem() { - this.id = UUID.randomUUID().toString(); - } - - public String getId() { - return id; - } - - public abstract int getType(); - - public abstract String getDetailString(); - - public abstract MaterialAboutItem clone(); - -} diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutItemOnChangeAction.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutItemOnChangeAction.java deleted file mode 100644 index 836883db..00000000 --- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutItemOnChangeAction.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.danielstone.materialaboutlibrary.items; - -public interface MaterialAboutItemOnChangeAction { - boolean onChange(boolean isChecked, int tag); -} diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutItemOnClickAction.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutItemOnClickAction.java deleted file mode 100644 index ca1cd610..00000000 --- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutItemOnClickAction.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.danielstone.materialaboutlibrary.items; - -public interface MaterialAboutItemOnClickAction { - void onClick(); -} diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutProfileItem.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutProfileItem.java deleted file mode 100644 index aeb4d4fe..00000000 --- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutProfileItem.java +++ /dev/null @@ -1,352 +0,0 @@ -package com.danielstone.materialaboutlibrary.items; - - -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.os.Build; -import androidx.annotation.DrawableRes; -import androidx.annotation.StringRes; - -import android.util.Log; -import android.util.TypedValue; -import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; - -import com.danielstone.materialaboutlibrary.R; -import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder; -import com.danielstone.materialaboutlibrary.util.ViewTypeManager; - -import static android.view.View.GONE; - -public class MaterialAboutProfileItem extends MaterialAboutItem { - - private CharSequence text = null; - private int textRes = 0; - private CharSequence desc = null; - private int descRes = 0; - private Drawable icon = null; - private int iconRes = 0; - private MaterialAboutItemOnClickAction onClickAction = null; - private MaterialAboutItemOnClickAction onLongClickAction = null; - - private MaterialAboutProfileItem(MaterialAboutProfileItem.Builder builder) { - super(); - this.text = builder.text; - this.textRes = builder.textRes; - - this.desc = builder.desc; - this.descRes = builder.descRes; - - this.icon = builder.icon; - this.iconRes = builder.iconRes; - - this.onClickAction = builder.onClickAction; - this.onLongClickAction = builder.onLongClickAction; - } - - public MaterialAboutProfileItem(CharSequence text, CharSequence desc, Drawable icon) { - this.text = text; - this.desc = desc; - this.icon = icon; - } - - public MaterialAboutProfileItem(int textRes, int descRes, int iconRes) { - this.textRes = textRes; - this.descRes = descRes; - this.iconRes = iconRes; - } - - public static MaterialAboutItemViewHolder getViewHolder(View view) { - return new MaterialAboutProfileItem.MaterialAboutProfileItemViewHolder(view); - } - - public static void setupItem(MaterialAboutProfileItemViewHolder holder, MaterialAboutProfileItem item, Context context) { - - CharSequence text = item.getText(); - int textRes = item.getTextRes(); - - holder.text.setVisibility(View.VISIBLE); - if (text != null) { - holder.text.setText(text); - } else if (textRes != 0) { - holder.text.setText(textRes); - } else { - holder.text.setVisibility(GONE); - } - - CharSequence desc = item.getDesc(); - int descRes = item.getDescRes(); - - holder.desc.setVisibility(View.VISIBLE); - if (desc != null) { - holder.desc.setText(desc); - } else if (descRes != 0) { - holder.desc.setText(descRes); - } else { - holder.desc.setVisibility(GONE); - } - - Drawable drawable = item.getIcon(); - int drawableRes = item.getIconRes(); - if (drawable != null) { - holder.icon.setImageDrawable(drawable); - } else if (drawableRes != 0) { - holder.icon.setImageResource(drawableRes); - } - - int pL = 0, pT = 0, pR = 0, pB = 0; - if (Build.VERSION.SDK_INT < 21) { - pL = holder.view.getPaddingLeft(); - pT = holder.view.getPaddingTop(); - pR = holder.view.getPaddingRight(); - pB = holder.view.getPaddingBottom(); - } - - if (item.getOnClickAction() != null || item.getOnLongClickAction() != null) { - TypedValue outValue = new TypedValue(); - context.getTheme().resolveAttribute(R.attr.selectableItemBackground, outValue, true); - holder.view.setBackgroundResource(outValue.resourceId); - } else { - holder.view.setBackgroundResource(0); - } - holder.setOnClickAction(item.getOnClickAction()); - holder.setOnLongClickAction(item.getOnLongClickAction()); - - if (Build.VERSION.SDK_INT < 21) { - holder.view.setPadding(pL, pT, pR, pB); - } - } - - @Override - public int getType() { - return ViewTypeManager.ItemType.PROFILE_ITEM; - } - - @Override - public String getDetailString() { - return "MaterialAboutProfileItem{" + - "text=" + text + - ", textRes=" + textRes + - ", desc=" + desc + - ", descRes=" + descRes + - ", icon=" + icon + - ", iconRes=" + iconRes + - ", onClickAction=" + onClickAction + - ", onLongClickAction=" + onLongClickAction + - '}'; - } - - public MaterialAboutProfileItem(MaterialAboutProfileItem item) { - this.id = item.getId(); - this.text = item.getText(); - this.textRes = item.getTextRes(); - this.desc = item.getDesc(); - this.descRes = item.getDescRes(); - this.icon = item.getIcon(); - this.iconRes = item.getIconRes(); - this.onClickAction = item.getOnClickAction(); - this.onLongClickAction = item.getOnLongClickAction(); - } - - @Override - public MaterialAboutProfileItem clone() { - return new MaterialAboutProfileItem(this); - } - - public CharSequence getText() { - return text; - } - - public MaterialAboutProfileItem setText(CharSequence text) { - this.textRes = 0; - this.text = text; - return this; - } - - public int getTextRes() { - return textRes; - } - - public MaterialAboutProfileItem setTextRes(int textRes) { - this.text = null; - this.textRes = textRes; - return this; - } - - public CharSequence getDesc() { - return desc; - } - - public MaterialAboutProfileItem setDesc(CharSequence desc) { - this.descRes = 0; - this.desc = desc; - return this; - } - - public int getDescRes() { - return descRes; - } - - public MaterialAboutProfileItem setDescRes(int descRes) { - this.desc = null; - this.descRes = textRes; - return this; - } - - public Drawable getIcon() { - return icon; - } - - public MaterialAboutProfileItem setIcon(Drawable icon) { - this.iconRes = 0; - this.icon = icon; - return this; - } - - public int getIconRes() { - return iconRes; - } - - public MaterialAboutProfileItem setIconRes(int iconRes) { - this.icon = null; - this.iconRes = iconRes; - return this; - } - - public MaterialAboutItemOnClickAction getOnClickAction() { - return onClickAction; - } - - public MaterialAboutProfileItem setOnClickAction(MaterialAboutItemOnClickAction onClickAction) { - this.onClickAction = onClickAction; - return this; - } - - public MaterialAboutItemOnClickAction getOnLongClickAction() { - return onLongClickAction; - } - - public MaterialAboutProfileItem setOnLongClickAction(MaterialAboutItemOnClickAction onLongClickAction) { - this.onLongClickAction = onLongClickAction; - return this; - } - public static class MaterialAboutProfileItemViewHolder extends MaterialAboutItemViewHolder implements View.OnClickListener, View.OnLongClickListener { - public final View view; - public final ImageView icon; - public final TextView text; - public final TextView desc; - private MaterialAboutItemOnClickAction onClickAction; - private MaterialAboutItemOnClickAction onLongClickAction; - - MaterialAboutProfileItemViewHolder(View view) { - super(view); - this.view = view; - icon = (ImageView) view.findViewById(R.id.mal_item_image); - text = (TextView) view.findViewById(R.id.mal_item_text); - desc = (TextView) view.findViewById(R.id.mal_item_desc); - } - - public void setOnClickAction(MaterialAboutItemOnClickAction onClickAction) { - this.onClickAction = onClickAction; - if (onClickAction != null) { - view.setOnClickListener(this); - } else { - view.setClickable(false); - } - } - - public void setOnLongClickAction(MaterialAboutItemOnClickAction onLongClickAction) { - this.onLongClickAction = onLongClickAction; - if (onLongClickAction != null) { - view.setOnLongClickListener(this); - } else { - view.setLongClickable(false); - } - } - - @Override - public void onClick(View v) { - if (onClickAction != null) { - onClickAction.onClick(); - } - } - - @Override - public boolean onLongClick(View v) { - if (onLongClickAction != null) { - onLongClickAction.onClick(); - return true; - } - return false; - } - } - - public static class Builder { - - MaterialAboutItemOnClickAction onClickAction = null; - MaterialAboutItemOnClickAction onLongClickAction = null; - private CharSequence text = null; - @StringRes - private int textRes = 0; - private CharSequence desc = null; - @StringRes - private int descRes = 0; - private Drawable icon = null; - @DrawableRes - private int iconRes = 0; - - public MaterialAboutProfileItem.Builder text(CharSequence text) { - this.text = text; - this.textRes = 0; - return this; - } - - - public MaterialAboutProfileItem.Builder text(@StringRes int text) { - this.textRes = text; - this.text = null; - return this; - } - - public MaterialAboutProfileItem.Builder desc(CharSequence desc) { - this.desc = desc; - this.descRes = 0; - return this; - } - - - public MaterialAboutProfileItem.Builder desc(@StringRes int desc) { - this.descRes = desc; - this.desc = null; - return this; - } - - public MaterialAboutProfileItem.Builder icon(Drawable icon) { - this.icon = icon; - this.iconRes = 0; - return this; - } - - - public MaterialAboutProfileItem.Builder icon(@DrawableRes int iconRes) { - this.icon = null; - this.iconRes = iconRes; - return this; - } - - public MaterialAboutProfileItem.Builder setOnClickAction(MaterialAboutItemOnClickAction onClickAction) { - this.onClickAction = onClickAction; - return this; - } - - public MaterialAboutProfileItem.Builder setOnLongClickAction(MaterialAboutItemOnClickAction onLongClickAction) { - this.onLongClickAction = onLongClickAction; - return this; - } - - public MaterialAboutProfileItem build() { - return new MaterialAboutProfileItem(this); - } - } -} diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutSwitchItem.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutSwitchItem.java deleted file mode 100644 index 4ce55683..00000000 --- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutSwitchItem.java +++ /dev/null @@ -1,548 +0,0 @@ -package com.danielstone.materialaboutlibrary.items; - -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.os.Build; -import androidx.annotation.DrawableRes; -import androidx.annotation.IntDef; -import androidx.annotation.StringRes; -import androidx.appcompat.widget.SwitchCompat; - -import android.text.Html; -import android.util.Log; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.View; -import android.widget.CompoundButton; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.Switch; -import android.widget.TextView; - -import com.danielstone.materialaboutlibrary.R; -import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder; -import com.danielstone.materialaboutlibrary.util.ViewTypeManager; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import static android.view.View.GONE; - -public class MaterialAboutSwitchItem extends MaterialAboutItem { - - public static final int GRAVITY_TOP = 0; - public static final int GRAVITY_MIDDLE = 1; - public static final int GRAVITY_BOTTOM = 2; - private CharSequence text = null; - private int textRes = 0; - private CharSequence subText = null; - private int subTextRes = 0; - private CharSequence subTextChecked = null; - private int subTextCheckedRes = 0; - private Drawable icon = null; - private int iconRes = 0; - private boolean showIcon = true; - private int iconGravity = GRAVITY_MIDDLE; - private boolean checked = false; - private int tag = -1; - private MaterialAboutItemOnChangeAction onChangeAction = null; - - private MaterialAboutSwitchItem(Builder builder) { - super(); - this.text = builder.text; - this.textRes = builder.textRes; - - this.subText = builder.subText; - this.subTextRes = builder.subTextRes; - - this.subTextChecked = builder.subTextChecked; - this.subTextCheckedRes = builder.subTextCheckedRes; - - this.icon = builder.icon; - this.iconRes = builder.iconRes; - - this.showIcon = builder.showIcon; - - this.iconGravity = builder.iconGravity; - - this.checked = builder.checked; - - this.tag = builder.tag; - - this.onChangeAction = builder.onChangeAction; - } - - public MaterialAboutSwitchItem(CharSequence text, CharSequence subText, Drawable icon, MaterialAboutItemOnChangeAction onChangeAction) { - this.text = text; - this.subText = subText; - this.icon = icon; - this.onChangeAction = onChangeAction; - } - - public MaterialAboutSwitchItem(CharSequence text, CharSequence subText, Drawable icon) { - this.text = text; - this.subText = subText; - this.icon = icon; - } - - public MaterialAboutSwitchItem(int textRes, int subTextRes, int iconRes, MaterialAboutItemOnChangeAction onChangeAction) { - this.textRes = textRes; - this.subTextRes = subTextRes; - this.iconRes = iconRes; - this.onChangeAction = onChangeAction; - } - - public MaterialAboutSwitchItem(int textRes, int subTextRes, int iconRes) { - this.textRes = textRes; - this.subTextRes = subTextRes; - this.iconRes = iconRes; - } - - public static void setupItem(MaterialAboutSwitchItemViewHolder holder, MaterialAboutSwitchItem item, Context context) { - holder.switchItem = item; - - CharSequence text = item.getText(); - int textRes = item.getTextRes(); - - holder.text.setVisibility(View.VISIBLE); - if (text != null) { - holder.text.setText(text); - } else if (textRes != 0) { - holder.text.setText(textRes); - } else { - holder.text.setVisibility(GONE); - } - - CharSequence subText = item.getSubText(); - int subTextRes = item.getSubTextRes(); - - holder.subText.setVisibility(View.VISIBLE); - if (subText != null) { - holder.subText.setText(subText); - } else if (subTextRes != 0) { - holder.subText.setText(subTextRes); - } else { - holder.subText.setVisibility(GONE); - } - - if (item.shouldShowIcon()) { - holder.icon.setVisibility(View.VISIBLE); - Drawable drawable = item.getIcon(); - int drawableRes = item.getIconRes(); - if (drawable != null) { - holder.icon.setImageDrawable(drawable); - } else if (drawableRes != 0) { - holder.icon.setImageResource(drawableRes); - } - } else { - holder.icon.setVisibility(GONE); - } - - LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) holder.icon.getLayoutParams(); - switch (item.getIconGravity()) { - case MaterialAboutSwitchItem.GRAVITY_TOP: - params.gravity = Gravity.TOP; - break; - case MaterialAboutSwitchItem.GRAVITY_MIDDLE: - params.gravity = Gravity.CENTER_VERTICAL; - break; - case MaterialAboutSwitchItem.GRAVITY_BOTTOM: - params.gravity = Gravity.BOTTOM; - break; - } - holder.icon.setLayoutParams(params); - - int pL = 0, pT = 0, pR = 0, pB = 0; - if (Build.VERSION.SDK_INT < 21) { - pL = holder.view.getPaddingLeft(); - pT = holder.view.getPaddingTop(); - pR = holder.view.getPaddingRight(); - pB = holder.view.getPaddingBottom(); - } - - holder.setChecked(item.getChecked()); - - if (item.getOnChangeAction() != null) { - TypedValue outValue = new TypedValue(); - context.getTheme().resolveAttribute(R.attr.selectableItemBackground, outValue, true); - holder.view.setBackgroundResource(outValue.resourceId); - } else { - holder.view.setBackgroundResource(0); - } - holder.setOnChangeAction(item.getOnChangeAction()); - - if (Build.VERSION.SDK_INT < 21) { - holder.view.setPadding(pL, pT, pR, pB); - } - } - - public static MaterialAboutItemViewHolder getViewHolder(View view) { - return new MaterialAboutSwitchItemViewHolder(view); - } - - public static class MaterialAboutSwitchItemViewHolder extends MaterialAboutItemViewHolder implements View.OnClickListener, CompoundButton.OnCheckedChangeListener { - public final View view; - public final ImageView icon; - public final TextView text; - public final TextView subText; - public final SwitchCompat switchView; - private MaterialAboutItemOnChangeAction onChangeAction; - private MaterialAboutSwitchItem switchItem; - - MaterialAboutSwitchItemViewHolder(View view) { - super(view); - this.view = view; - icon = view.findViewById(R.id.mal_item_image); - text = view.findViewById(R.id.mal_item_text); - subText = view.findViewById(R.id.mal_action_item_subtext); - switchView = view.findViewById(R.id.mal_switch); - } - - public void setOnChangeAction(MaterialAboutItemOnChangeAction onChangeAction) { - this.onChangeAction = onChangeAction; - view.setOnClickListener(onChangeAction != null ? this : null); - switchView.setOnCheckedChangeListener(this); - } - - public void setChecked(boolean checked) { - switchView.setOnCheckedChangeListener(null); - switchView.setChecked(checked); - switchView.setOnCheckedChangeListener(this); - switchItem.setChecked(checked); - updateSubText(checked); - } - - public void updateSubText(boolean checked) { - if (checked && switchItem.subTextChecked != null) { - subText.setText(switchItem.subTextChecked); - } - else if (checked && switchItem.subTextCheckedRes != 0) { - subText.setText(switchItem.subTextCheckedRes); - } - else if (switchItem.subText != null) { - subText.setText(switchItem.subText); - } - else if (switchItem.subTextRes != 0) { - subText.setText(switchItem.subTextRes); - } - } - - @Override - public void onClick(View v) { - switchView.toggle(); - } - - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - updateSubText(isChecked); - if (onChangeAction != null) { - if (!onChangeAction.onChange(isChecked, switchItem.getTag())) { - setChecked(!isChecked); - } - else { - switchItem.setChecked(isChecked); - } - } - else { - setChecked(!isChecked); - } - } - } - - @Override - public int getType() { - return ViewTypeManager.ItemType.SWITCH_ITEM; - } - - @Override - public String getDetailString() { - return "MaterialAboutSwitchItem{" + - "text=" + text + - ", textRes=" + textRes + - ", subText=" + subText + - ", subTextRes=" + subTextRes + - ", subTextChecked=" + subTextChecked + - ", subTextCheckedRes=" + subTextCheckedRes + - ", icon=" + icon + - ", iconRes=" + iconRes + - ", showIcon=" + showIcon + - ", iconGravity=" + iconGravity + - ", checked=" + checked + - ", tag=" + tag + - ", onChangeAction=" + onChangeAction + - '}'; - } - - public MaterialAboutSwitchItem(MaterialAboutSwitchItem item) { - this.id = item.getId(); - this.text = item.getText(); - this.textRes = item.getTextRes(); - this.subText = item.getSubText(); - this.subTextRes = item.getSubTextRes(); - this.subTextChecked = item.getSubTextChecked(); - this.subTextCheckedRes = item.getSubTextCheckedRes(); - this.icon = item.getIcon(); - this.iconRes = item.getIconRes(); - this.showIcon = item.showIcon; - this.iconGravity = item.iconGravity; - this.checked = item.checked; - this.tag = item.tag; - this.onChangeAction = item.onChangeAction; - } - - @Override - public MaterialAboutItem clone() { - return new MaterialAboutSwitchItem(this); - } - - public int getTag() { - return tag; - } - public MaterialAboutSwitchItem setTag(int tag) { - this.tag = tag; - return this; - } - - public CharSequence getText() { - return text; - } - public MaterialAboutSwitchItem setText(CharSequence text) { - this.textRes = 0; - this.text = text; - return this; - } - - public int getTextRes() { - return textRes; - } - - public MaterialAboutSwitchItem setTextRes(int textRes) { - this.text = null; - this.textRes = textRes; - return this; - } - - public CharSequence getSubText() { - return subText; - } - - public MaterialAboutSwitchItem setSubText(CharSequence subText) { - this.subTextRes = 0; - this.subText = subText; - return this; - } - - public int getSubTextRes() { - return subTextRes; - } - - public MaterialAboutSwitchItem setSubTextRes(int subTextRes) { - this.subText = null; - this.subTextRes = subTextRes; - return this; - } - - public CharSequence getSubTextChecked() { - return subTextChecked; - } - - public MaterialAboutSwitchItem setSubTextChecked(CharSequence subTextChecked) { - this.subTextCheckedRes = 0; - this.subTextChecked = subTextChecked; - return this; - } - - public int getSubTextCheckedRes() { - return subTextCheckedRes; - } - - public MaterialAboutSwitchItem setSubTextCheckedRes(int subTextCheckedRes) { - this.subTextChecked = null; - this.subTextCheckedRes = subTextCheckedRes; - return this; - } - - public Drawable getIcon() { - return icon; - } - - public MaterialAboutSwitchItem setIcon(Drawable icon) { - this.iconRes = 0; - this.icon = icon; - return this; - } - - public int getIconRes() { - return iconRes; - } - - public MaterialAboutSwitchItem setIconRes(int iconRes) { - this.icon = null; - this.iconRes = iconRes; - return this; - } - - public boolean shouldShowIcon() { - return showIcon; - } - - public MaterialAboutSwitchItem setShouldShowIcon(boolean showIcon) { - this.showIcon = showIcon; - return this; - } - - @IconGravity - public int getIconGravity() { - return iconGravity; - } - - public MaterialAboutSwitchItem setIconGravity(int iconGravity) { - this.iconGravity = iconGravity; - return this; - } - - public boolean getChecked() { - return checked; - } - - public MaterialAboutSwitchItem setChecked(boolean checked) { - //Log.d("MaterialItem", "Setting item "+getText()+" to checked "+checked); - this.checked = checked; - return this; - } - - public MaterialAboutItemOnChangeAction getOnChangeAction() { - return onChangeAction; - } - - public MaterialAboutSwitchItem setOnChangeAction(MaterialAboutItemOnChangeAction onChangeAction) { - this.onChangeAction = onChangeAction; - return this; - } - - @Retention(RetentionPolicy.SOURCE) - @IntDef({GRAVITY_TOP, GRAVITY_MIDDLE, GRAVITY_BOTTOM}) - public @interface IconGravity { - } - - public static class Builder { - - MaterialAboutItemOnChangeAction onChangeAction = null; - private CharSequence text = null; - @StringRes - private int textRes = 0; - private CharSequence subText = null; - @StringRes - private int subTextRes = 0; - private CharSequence subTextChecked = null; - @StringRes - private int subTextCheckedRes = 0; - private Drawable icon = null; - @DrawableRes - private int iconRes = 0; - private boolean showIcon = true; - @IconGravity - private int iconGravity = GRAVITY_MIDDLE; - private boolean checked = false; - private int tag = -1; - - public Builder tag(int tag) { - this.tag = tag; - return this; - } - - public Builder text(CharSequence text) { - this.text = text; - this.textRes = 0; - return this; - } - - public Builder text(@StringRes int text) { - this.textRes = text; - this.text = null; - return this; - } - - public Builder subText(CharSequence subText) { - this.subText = subText; - this.subTextRes = 0; - return this; - } - - public Builder subText(@StringRes int subTextRes) { - this.subText = null; - this.subTextRes = subTextRes; - return this; - } - - public Builder subTextHtml(String subTextHtml) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - this.subText = Html.fromHtml(subTextHtml, Html.FROM_HTML_MODE_LEGACY); - } else { - //noinspection deprecation - this.subText = Html.fromHtml(subTextHtml); - } - this.subTextRes = 0; - return this; - } - - public Builder subTextChecked(CharSequence subTextChecked) { - this.subTextChecked = subTextChecked; - this.subTextCheckedRes = 0; - return this; - } - - public Builder subTextChecked(@StringRes int subTextCheckedRes) { - this.subTextChecked = null; - this.subTextCheckedRes = subTextCheckedRes; - return this; - } - - public Builder subTextCheckedHtml(String subTextCheckedHtml) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - this.subTextChecked = Html.fromHtml(subTextCheckedHtml, Html.FROM_HTML_MODE_LEGACY); - } else { - //noinspection deprecation - this.subTextChecked = Html.fromHtml(subTextCheckedHtml); - } - this.subTextCheckedRes = 0; - return this; - } - - public Builder icon(Drawable icon) { - this.icon = icon; - this.iconRes = 0; - return this; - } - - public Builder icon(@DrawableRes int iconRes) { - this.icon = null; - this.iconRes = iconRes; - return this; - } - - public Builder showIcon(boolean showIcon) { - this.showIcon = showIcon; - return this; - } - - public Builder setIconGravity(@IconGravity int iconGravity) { - this.iconGravity = iconGravity; - return this; - } - - public Builder setOnChangeAction(MaterialAboutItemOnChangeAction onChangeAction) { - this.onChangeAction = onChangeAction; - return this; - } - - public Builder checked(boolean isChecked) { - this.checked = isChecked; - return this; - } - - public MaterialAboutSwitchItem build() { - return new MaterialAboutSwitchItem(this); - } - } -} diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutTitleItem.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutTitleItem.java deleted file mode 100644 index a1b1bc72..00000000 --- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutTitleItem.java +++ /dev/null @@ -1,400 +0,0 @@ -package com.danielstone.materialaboutlibrary.items; - - -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.os.Build; - -import androidx.annotation.ColorInt; -import androidx.annotation.DrawableRes; -import androidx.annotation.StringRes; -import android.util.TypedValue; -import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; - -import com.danielstone.materialaboutlibrary.R; -import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder; -import com.danielstone.materialaboutlibrary.util.ViewTypeManager; - -import static android.view.View.GONE; - -public class MaterialAboutTitleItem extends MaterialAboutItem { - - private CharSequence text = null; - private int textRes = 0; - private CharSequence desc = null; - private int descRes = 0; - private int textColor = -1; - private int descColor = -1; - private Drawable icon = null; - private int iconRes = 0; - private MaterialAboutItemOnClickAction onClickAction = null; - private MaterialAboutItemOnClickAction onLongClickAction = null; - - private MaterialAboutTitleItem(MaterialAboutTitleItem.Builder builder) { - super(); - this.text = builder.text; - this.textRes = builder.textRes; - - this.desc = builder.desc; - this.descRes = builder.descRes; - - this.textColor = builder.textColor; - this.descColor = builder.descColor; - - this.icon = builder.icon; - this.iconRes = builder.iconRes; - - this.onClickAction = builder.onClickAction; - this.onLongClickAction = builder.onLongClickAction; - } - - public MaterialAboutTitleItem(CharSequence text, CharSequence desc, Drawable icon) { - this.text = text; - this.desc = desc; - this.icon = icon; - } - - public MaterialAboutTitleItem(int textRes, int descRes, int iconRes) { - this.textRes = textRes; - this.descRes = descRes; - this.iconRes = iconRes; - } - - public static MaterialAboutItemViewHolder getViewHolder(View view) { - return new MaterialAboutTitleItem.MaterialAboutTitleItemViewHolder(view); - } - - public static void setupItem(MaterialAboutTitleItemViewHolder holder, MaterialAboutTitleItem item, Context context) { - - CharSequence text = item.getText(); - int textRes = item.getTextRes(); - - holder.text.setVisibility(View.VISIBLE); - if (text != null) { - holder.text.setText(text); - } else if (textRes != 0) { - holder.text.setText(textRes); - } else { - holder.text.setVisibility(GONE); - } - - CharSequence desc = item.getDesc(); - int descRes = item.getDescRes(); - - holder.desc.setVisibility(View.VISIBLE); - if (desc != null) { - holder.desc.setText(desc); - } else if (descRes != 0) { - holder.desc.setText(descRes); - } else { - holder.desc.setVisibility(GONE); - } - - if (item.getTextColor() != -1) { - holder.text.setTextColor(item.getTextColor()); - } - if (item.getDescColor() != -1) { - holder.desc.setTextColor(item.getDescColor()); - } - - Drawable drawable = item.getIcon(); - int drawableRes = item.getIconRes(); - if (drawable != null) { - holder.icon.setImageDrawable(drawable); - } else if (drawableRes != 0) { - holder.icon.setImageResource(drawableRes); - } - - int pL = 0, pT = 0, pR = 0, pB = 0; - if (Build.VERSION.SDK_INT < 21) { - pL = holder.view.getPaddingLeft(); - pT = holder.view.getPaddingTop(); - pR = holder.view.getPaddingRight(); - pB = holder.view.getPaddingBottom(); - } - - if (item.getOnClickAction() != null || item.getOnLongClickAction() != null) { - TypedValue outValue = new TypedValue(); - context.getTheme().resolveAttribute(R.attr.selectableItemBackground, outValue, true); - holder.view.setBackgroundResource(outValue.resourceId); - } else { - holder.view.setBackgroundResource(0); - } - holder.setOnClickAction(item.getOnClickAction()); - holder.setOnLongClickAction(item.getOnLongClickAction()); - - if (Build.VERSION.SDK_INT < 21) { - holder.view.setPadding(pL, pT, pR, pB); - } - } - - @Override - public int getType() { - return ViewTypeManager.ItemType.TITLE_ITEM; - } - - @Override - public String getDetailString() { - return "MaterialAboutTitleItem{" + - "text=" + text + - ", textRes=" + textRes + - ", desc=" + desc + - ", descRes=" + descRes + - ", textColor=" + textColor + - ", descColor=" + descColor + - ", icon=" + icon + - ", iconRes=" + iconRes + - ", onClickAction=" + onClickAction + - ", onLongClickAction=" + onLongClickAction + - '}'; - } - - public MaterialAboutTitleItem(MaterialAboutTitleItem item) { - this.id = item.getId(); - this.text = item.getText(); - this.textRes = item.getTextRes(); - this.desc = item.getDesc(); - this.descRes = item.getDescRes(); - this.textColor = item.getTextColor(); - this.descColor = item.getDescColor(); - this.icon = item.getIcon(); - this.iconRes = item.getIconRes(); - this.onClickAction = item.getOnClickAction(); - this.onLongClickAction = item.getOnLongClickAction(); - } - - @Override - public MaterialAboutTitleItem clone() { - return new MaterialAboutTitleItem(this); - } - - public CharSequence getText() { - return text; - } - - public MaterialAboutTitleItem setText(CharSequence text) { - this.textRes = 0; - this.text = text; - return this; - } - - public int getTextRes() { - return textRes; - } - - public MaterialAboutTitleItem setTextRes(int textRes) { - this.text = null; - this.textRes = textRes; - return this; - } - - public CharSequence getDesc() { - return desc; - } - - public MaterialAboutTitleItem setDesc(CharSequence desc) { - this.descRes = 0; - this.desc = desc; - return this; - } - - public int getDescRes() { - return descRes; - } - - public MaterialAboutTitleItem setDescRes(int descRes) { - this.desc = null; - this.descRes = textRes; - return this; - } - - public int getTextColor() { - return textColor; - } - - public MaterialAboutTitleItem setTextColor(int textColor) { - this.textColor = textColor; - return this; - } - - public int getDescColor() { - return descColor; - } - - public MaterialAboutTitleItem setDescColor(int descColor) { - this.descColor = descColor; - return this; - } - - public Drawable getIcon() { - return icon; - } - - public MaterialAboutTitleItem setIcon(Drawable icon) { - this.iconRes = 0; - this.icon = icon; - return this; - } - - public int getIconRes() { - return iconRes; - } - - public MaterialAboutTitleItem setIconRes(int iconRes) { - this.icon = null; - this.iconRes = iconRes; - return this; - } - - public MaterialAboutItemOnClickAction getOnClickAction() { - return onClickAction; - } - - public MaterialAboutTitleItem setOnClickAction(MaterialAboutItemOnClickAction onClickAction) { - this.onClickAction = onClickAction; - return this; - } - - public MaterialAboutItemOnClickAction getOnLongClickAction() { - return onLongClickAction; - } - - public MaterialAboutTitleItem setOnLongClickAction(MaterialAboutItemOnClickAction onLongClickAction) { - this.onLongClickAction = onLongClickAction; - return this; - } - public static class MaterialAboutTitleItemViewHolder extends MaterialAboutItemViewHolder implements View.OnClickListener, View.OnLongClickListener { - public final View view; - public final ImageView icon; - public final TextView text; - public final TextView desc; - private MaterialAboutItemOnClickAction onClickAction; - private MaterialAboutItemOnClickAction onLongClickAction; - - MaterialAboutTitleItemViewHolder(View view) { - super(view); - this.view = view; - icon = (ImageView) view.findViewById(R.id.mal_item_image); - text = (TextView) view.findViewById(R.id.mal_item_text); - desc = (TextView) view.findViewById(R.id.mal_item_desc); - } - - public void setOnClickAction(MaterialAboutItemOnClickAction onClickAction) { - this.onClickAction = onClickAction; - if (onClickAction != null) { - view.setOnClickListener(this); - } else { - view.setClickable(false); - } - } - - public void setOnLongClickAction(MaterialAboutItemOnClickAction onLongClickAction) { - this.onLongClickAction = onLongClickAction; - if (onLongClickAction != null) { - view.setOnLongClickListener(this); - } else { - view.setLongClickable(false); - } - } - - @Override - public void onClick(View v) { - if (onClickAction != null) { - onClickAction.onClick(); - } - } - - @Override - public boolean onLongClick(View v) { - if (onLongClickAction != null) { - onLongClickAction.onClick(); - return true; - } - return false; - } - } - - public static class Builder { - - MaterialAboutItemOnClickAction onClickAction = null; - MaterialAboutItemOnClickAction onLongClickAction = null; - private CharSequence text = null; - @StringRes - private int textRes = 0; - private CharSequence desc = null; - @StringRes - private int descRes = 0; - @ColorInt - private int textColor = -1; - @ColorInt - private int descColor = -1; - private Drawable icon = null; - @DrawableRes - private int iconRes = 0; - - public MaterialAboutTitleItem.Builder text(CharSequence text) { - this.text = text; - this.textRes = 0; - return this; - } - - - public MaterialAboutTitleItem.Builder text(@StringRes int text) { - this.textRes = text; - this.text = null; - return this; - } - - public MaterialAboutTitleItem.Builder desc(CharSequence desc) { - this.desc = desc; - this.descRes = 0; - return this; - } - - - public MaterialAboutTitleItem.Builder desc(@StringRes int desc) { - this.descRes = desc; - this.desc = null; - return this; - } - - public MaterialAboutTitleItem.Builder textColor(@ColorInt int textColor) { - this.textColor = textColor; - return this; - } - - public MaterialAboutTitleItem.Builder descColor(@ColorInt int descColor) { - this.descColor = descColor; - return this; - } - - public MaterialAboutTitleItem.Builder icon(Drawable icon) { - this.icon = icon; - this.iconRes = 0; - return this; - } - - - public MaterialAboutTitleItem.Builder icon(@DrawableRes int iconRes) { - this.icon = null; - this.iconRes = iconRes; - return this; - } - - public MaterialAboutTitleItem.Builder setOnClickAction(MaterialAboutItemOnClickAction onClickAction) { - this.onClickAction = onClickAction; - return this; - } - - public MaterialAboutTitleItem.Builder setOnLongClickAction(MaterialAboutItemOnClickAction onLongClickAction) { - this.onLongClickAction = onLongClickAction; - return this; - } - - public MaterialAboutTitleItem build() { - return new MaterialAboutTitleItem(this); - } - } -} diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/model/MaterialAboutCard.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/model/MaterialAboutCard.java deleted file mode 100644 index ecbffb18..00000000 --- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/model/MaterialAboutCard.java +++ /dev/null @@ -1,156 +0,0 @@ -package com.danielstone.materialaboutlibrary.model; - - -import androidx.annotation.ColorInt; -import androidx.annotation.StringRes; -import androidx.annotation.StyleRes; -import androidx.recyclerview.widget.RecyclerView; - -import com.danielstone.materialaboutlibrary.items.MaterialAboutItem; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.UUID; - -public class MaterialAboutCard { - - private String id = "NO-UUID"; - - private CharSequence title = null; - private int titleRes = 0; - - private int titleColor = 0; - private int cardColor = 0; - - private RecyclerView.Adapter customAdapter = null; - private ArrayList items = new ArrayList<>(); - - - private MaterialAboutCard(Builder builder) { - this.id = UUID.randomUUID().toString(); - this.title = builder.title; - this.titleRes = builder.titleRes; - this.titleColor = builder.titleColor; - this.cardColor = builder.cardColor; - this.items = builder.items; - this.customAdapter = builder.customAdapter; - } - - public MaterialAboutCard(CharSequence title, MaterialAboutItem... materialAboutItems) { - this.title = title; - Collections.addAll(items, materialAboutItems); - } - - public MaterialAboutCard(int titleRes, MaterialAboutItem... materialAboutItems) { - this.titleRes = titleRes; - Collections.addAll(items, materialAboutItems); - } - - public CharSequence getTitle() { - return title; - } - - public int getTitleRes() { - return titleRes; - } - - public int getTitleColor() { - return titleColor; - } - - public int getCardColor() { - return cardColor; - } - - public ArrayList getItems() { - return items; - } - - public static class Builder { - private CharSequence title = null; - @StringRes - private int titleRes = 0; - - @ColorInt - private int titleColor = 0; - - @ColorInt - private int cardColor = 0; - - private ArrayList items = new ArrayList<>(); - private RecyclerView.Adapter customAdapter = null; - - public Builder title(CharSequence title) { - this.title = title; - this.titleRes = 0; - return this; - } - - public Builder title(@StringRes int titleRes) { - this.titleRes = titleRes; - this.title = null; - return this; - } - - public Builder titleColor(@ColorInt int color) { - this.titleColor = color; - return this; - } - - public Builder cardColor(@ColorInt int cardColor) { - this.cardColor = cardColor; - return this; - } - - public Builder addItem(MaterialAboutItem item) { - this.items.add(item); - return this; - } - - public Builder customAdapter(RecyclerView.Adapter customAdapter) { - this.customAdapter = customAdapter; - return this; - } - - public MaterialAboutCard build() { - return new MaterialAboutCard(this); - } - } - - public String getId() { - return id; - } - - public RecyclerView.Adapter getCustomAdapter() { - return customAdapter; - } - - @Override - public String toString() { - String result = "MaterialAboutCard{" + - "id='" + id + '\'' + - ", title=" + title + - ", titleRes=" + titleRes + - ", titleColor=" + titleColor + - ", customAdapter=" + customAdapter + - ", cardColor=" + cardColor + '}'; - return result; - } - - public MaterialAboutCard(MaterialAboutCard card) { - this.id = card.getId(); - this.title = card.getTitle(); - this.titleRes = card.getTitleRes(); - this.titleColor = card.getTitleColor(); - this.cardColor = card.getCardColor(); - this.items = new ArrayList<>(); - this.customAdapter = card.getCustomAdapter(); - for (MaterialAboutItem item : card.items) { - this.items.add(item.clone()); - } - } - public MaterialAboutCard clone() { - return new MaterialAboutCard(this); - } - -} diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/model/MaterialAboutList.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/model/MaterialAboutList.java deleted file mode 100644 index 910dcc53..00000000 --- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/model/MaterialAboutList.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.danielstone.materialaboutlibrary.model; - - -import java.util.ArrayList; -import java.util.Collections; - -public class MaterialAboutList { - - private ArrayList cards = new ArrayList<>(); - - private MaterialAboutList(Builder builder) { - this.cards = builder.cards; - } - - public MaterialAboutList(MaterialAboutCard... materialAboutCards) { - Collections.addAll(cards, materialAboutCards); - } - - public MaterialAboutList addCard(MaterialAboutCard card) { - cards.add(card); - return this; - } - - public MaterialAboutList clearCards(MaterialAboutCard card) { - cards.clear(); - return this; - } - - public ArrayList getCards() { - return cards; - } - - public static class Builder { - private ArrayList cards = new ArrayList<>(); - - public Builder addCard(MaterialAboutCard card) { - this.cards.add(card); - return this; - } - - public MaterialAboutList build() { - return new MaterialAboutList(this); - } - } -} diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/util/DefaultViewTypeManager.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/util/DefaultViewTypeManager.java deleted file mode 100644 index 8097c972..00000000 --- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/util/DefaultViewTypeManager.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.danielstone.materialaboutlibrary.util; - -import android.content.Context; -import android.view.View; - -import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder; -import com.danielstone.materialaboutlibrary.items.MaterialAboutActionItem; -import com.danielstone.materialaboutlibrary.items.MaterialAboutActionSwitchItem; -import com.danielstone.materialaboutlibrary.items.MaterialAboutCheckboxItem; -import com.danielstone.materialaboutlibrary.items.MaterialAboutItem; -import com.danielstone.materialaboutlibrary.items.MaterialAboutProfileItem; -import com.danielstone.materialaboutlibrary.items.MaterialAboutSwitchItem; -import com.danielstone.materialaboutlibrary.items.MaterialAboutTitleItem; - -import static com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager.ItemLayout.ACTION_LAYOUT; -import static com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager.ItemLayout.ACTION_SWITCH_LAYOUT; -import static com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager.ItemLayout.CHECKBOX_LAYOUT; -import static com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager.ItemLayout.PROFILE_LAYOUT; -import static com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager.ItemLayout.SWITCH_LAYOUT; -import static com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager.ItemLayout.TITLE_LAYOUT; -import static com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager.ItemType.ACTION_ITEM; -import static com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager.ItemType.ACTION_SWITCH_ITEM; -import static com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager.ItemType.CHECKBOX_ITEM; -import static com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager.ItemType.PROFILE_ITEM; -import static com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager.ItemType.SWITCH_ITEM; -import static com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager.ItemType.TITLE_ITEM; - -public class DefaultViewTypeManager extends ViewTypeManager { - - public static final class ItemType { - public static final int ACTION_ITEM = ViewTypeManager.ItemType.ACTION_ITEM; - public static final int TITLE_ITEM = ViewTypeManager.ItemType.TITLE_ITEM; - public static final int SWITCH_ITEM = ViewTypeManager.ItemType.SWITCH_ITEM; - public static final int ACTION_SWITCH_ITEM = ViewTypeManager.ItemType.ACTION_SWITCH_ITEM; - public static final int CHECKBOX_ITEM = ViewTypeManager.ItemType.CHECKBOX_ITEM; - public static final int PROFILE_ITEM = ViewTypeManager.ItemType.PROFILE_ITEM; - } - - public static final class ItemLayout { - public static final int ACTION_LAYOUT = ViewTypeManager.ItemLayout.ACTION_LAYOUT; - public static final int TITLE_LAYOUT = ViewTypeManager.ItemLayout.TITLE_LAYOUT; - public static final int SWITCH_LAYOUT = ViewTypeManager.ItemLayout.SWITCH_LAYOUT; - public static final int ACTION_SWITCH_LAYOUT = ViewTypeManager.ItemLayout.ACTION_SWITCH_LAYOUT; - public static final int CHECKBOX_LAYOUT = ViewTypeManager.ItemLayout.CHECKBOX_LAYOUT; - public static final int PROFILE_LAYOUT = ViewTypeManager.ItemLayout.PROFILE_LAYOUT; - } - - public int getLayout(int itemType) { - switch (itemType) { - case ACTION_ITEM: - return ACTION_LAYOUT; - case TITLE_ITEM: - return TITLE_LAYOUT; - case SWITCH_ITEM: - return SWITCH_LAYOUT; - case ACTION_SWITCH_ITEM: - return ACTION_SWITCH_LAYOUT; - case CHECKBOX_ITEM: - return CHECKBOX_LAYOUT; - case PROFILE_ITEM: - return PROFILE_LAYOUT; - default: - return -1; - } - } - - public MaterialAboutItemViewHolder getViewHolder(int itemType, View view) { - switch (itemType) { - case ACTION_ITEM: - return MaterialAboutActionItem.getViewHolder(view); - case TITLE_ITEM: - return MaterialAboutTitleItem.getViewHolder(view); - case SWITCH_ITEM: - return MaterialAboutSwitchItem.getViewHolder(view); - case ACTION_SWITCH_ITEM: - return MaterialAboutActionSwitchItem.getViewHolder(view); - case CHECKBOX_ITEM: - return MaterialAboutCheckboxItem.getViewHolder(view); - case PROFILE_ITEM: - return MaterialAboutProfileItem.getViewHolder(view); - default: - return null; - } - } - - public void setupItem(int itemType, MaterialAboutItemViewHolder holder, MaterialAboutItem item, Context context) { - switch (itemType) { - case ACTION_ITEM: - MaterialAboutActionItem.setupItem((MaterialAboutActionItem.MaterialAboutActionItemViewHolder) holder, (MaterialAboutActionItem) item, context); - break; - case TITLE_ITEM: - MaterialAboutTitleItem.setupItem((MaterialAboutTitleItem.MaterialAboutTitleItemViewHolder) holder, (MaterialAboutTitleItem) item, context); - break; - case SWITCH_ITEM: - MaterialAboutSwitchItem.setupItem((MaterialAboutSwitchItem.MaterialAboutSwitchItemViewHolder) holder, (MaterialAboutSwitchItem) item, context); - break; - case ACTION_SWITCH_ITEM: - MaterialAboutActionSwitchItem.setupItem((MaterialAboutActionSwitchItem.MaterialAboutActionSwitchItemViewHolder) holder, (MaterialAboutActionSwitchItem) item, context); - break; - case CHECKBOX_ITEM: - MaterialAboutCheckboxItem.setupItem((MaterialAboutCheckboxItem.MaterialAboutCheckboxItemViewHolder) holder, (MaterialAboutCheckboxItem) item, context); - break; - case PROFILE_ITEM: - MaterialAboutProfileItem.setupItem((MaterialAboutProfileItem.MaterialAboutProfileItemViewHolder) holder, (MaterialAboutProfileItem) item, context); - break; - } - } -} diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/util/OpenSourceLicense.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/util/OpenSourceLicense.java deleted file mode 100644 index c916b2b6..00000000 --- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/util/OpenSourceLicense.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.danielstone.materialaboutlibrary.util; - -import com.danielstone.materialaboutlibrary.R; - -public enum OpenSourceLicense { - APACHE_2, MIT, GNU_GPL_3, BSD; - - public int getResourceId() { - switch (this) { - case APACHE_2: - return R.string.license_apache2; - case MIT: - return R.string.license_mit; - case GNU_GPL_3: - return R.string.license_gpl; - case BSD: - return R.string.license_bsd; - default: - return -1; - } - } -} diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/util/ViewTypeManager.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/util/ViewTypeManager.java deleted file mode 100644 index d496dadd..00000000 --- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/util/ViewTypeManager.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.danielstone.materialaboutlibrary.util; - -import android.content.Context; -import android.view.View; - -import com.danielstone.materialaboutlibrary.R; -import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder; -import com.danielstone.materialaboutlibrary.items.MaterialAboutItem; - -public abstract class ViewTypeManager { - - public static final class ItemType { - public static final int ACTION_ITEM = 0; - public static final int TITLE_ITEM = 1; - public static final int SWITCH_ITEM = 2; - public static final int ACTION_SWITCH_ITEM = 3; - public static final int CHECKBOX_ITEM = 4; - public static final int PROFILE_ITEM = 5; - } - - public static final class ItemLayout { - public static final int ACTION_LAYOUT = R.layout.mal_material_about_action_item; - public static final int TITLE_LAYOUT = R.layout.mal_material_about_title_item; - public static final int SWITCH_LAYOUT = R.layout.mal_material_about_switch_item; - public static final int ACTION_SWITCH_LAYOUT = R.layout.mal_material_about_action_switch_item; - public static final int CHECKBOX_LAYOUT = R.layout.mal_material_about_checkbox_item; - public static final int PROFILE_LAYOUT = R.layout.mal_material_about_profile_item; - } - - public abstract int getLayout(int itemType); - - public abstract MaterialAboutItemViewHolder getViewHolder(int itemType, View view); - - public abstract void setupItem(int itemType, MaterialAboutItemViewHolder holder, MaterialAboutItem item, Context context); -} diff --git a/material-about-library/src/main/res/layout/mal_material_about_action_item.xml b/material-about-library/src/main/res/layout/mal_material_about_action_item.xml deleted file mode 100644 index 5edc81d4..00000000 --- a/material-about-library/src/main/res/layout/mal_material_about_action_item.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/material-about-library/src/main/res/layout/mal_material_about_action_switch_item.xml b/material-about-library/src/main/res/layout/mal_material_about_action_switch_item.xml deleted file mode 100644 index 9e1dd978..00000000 --- a/material-about-library/src/main/res/layout/mal_material_about_action_switch_item.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/material-about-library/src/main/res/layout/mal_material_about_activity.xml b/material-about-library/src/main/res/layout/mal_material_about_activity.xml deleted file mode 100644 index 42f77361..00000000 --- a/material-about-library/src/main/res/layout/mal_material_about_activity.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - diff --git a/material-about-library/src/main/res/layout/mal_material_about_checkbox_item.xml b/material-about-library/src/main/res/layout/mal_material_about_checkbox_item.xml deleted file mode 100644 index 659bbd1f..00000000 --- a/material-about-library/src/main/res/layout/mal_material_about_checkbox_item.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/material-about-library/src/main/res/layout/mal_material_about_fragment.xml b/material-about-library/src/main/res/layout/mal_material_about_fragment.xml deleted file mode 100644 index f8bdb8e0..00000000 --- a/material-about-library/src/main/res/layout/mal_material_about_fragment.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/material-about-library/src/main/res/layout/mal_material_about_list_card.xml b/material-about-library/src/main/res/layout/mal_material_about_list_card.xml deleted file mode 100644 index 0d1f73e8..00000000 --- a/material-about-library/src/main/res/layout/mal_material_about_list_card.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/material-about-library/src/main/res/layout/mal_material_about_profile_item.xml b/material-about-library/src/main/res/layout/mal_material_about_profile_item.xml deleted file mode 100644 index a90ccba1..00000000 --- a/material-about-library/src/main/res/layout/mal_material_about_profile_item.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/material-about-library/src/main/res/layout/mal_material_about_switch_item.xml b/material-about-library/src/main/res/layout/mal_material_about_switch_item.xml deleted file mode 100644 index b888bc0f..00000000 --- a/material-about-library/src/main/res/layout/mal_material_about_switch_item.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/material-about-library/src/main/res/layout/mal_material_about_title_item.xml b/material-about-library/src/main/res/layout/mal_material_about_title_item.xml deleted file mode 100644 index e77e04c8..00000000 --- a/material-about-library/src/main/res/layout/mal_material_about_title_item.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/material-about-library/src/main/res/values/attrs.xml b/material-about-library/src/main/res/values/attrs.xml deleted file mode 100644 index 9d555688..00000000 --- a/material-about-library/src/main/res/values/attrs.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/material-about-library/src/main/res/values/colors.xml b/material-about-library/src/main/res/values/colors.xml deleted file mode 100644 index 057f6cb3..00000000 --- a/material-about-library/src/main/res/values/colors.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - #de000000 - #8a000000 - - #ff9b9b9b - \ No newline at end of file diff --git a/material-about-library/src/main/res/values/dimens.xml b/material-about-library/src/main/res/values/dimens.xml deleted file mode 100644 index 06796bac..00000000 --- a/material-about-library/src/main/res/values/dimens.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - 16dp - 8dp - - 24dp - 32dp - 40dp - - 4dp - 4dp - - - \ No newline at end of file diff --git a/material-about-library/src/main/res/values/strings.xml b/material-about-library/src/main/res/values/strings.xml deleted file mode 100644 index cbe49a18..00000000 --- a/material-about-library/src/main/res/values/strings.xml +++ /dev/null @@ -1,94 +0,0 @@ - - - About - - Close - Send email - - No apps to handle action - - - "\nCopyright %1$s %2$s\n" - - "\nLicensed under the Apache License, Version 2.0 (the \"License\");" - "you may not use this file except in compliance with the License." - "You may obtain a copy of the License at\n" - - "\nhttp://www.apache.org/licenses/LICENSE-2.0\n" - - "\nUnless required by applicable law or agreed to in writing, software" - "distributed under the License is distributed on an \"AS IS\" BASIS," - "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied." - "See the License for the specific language governing permissions and" - "limitations under the License." - - - - "\nMIT License\n" - - "\nCopyright © %1$s %2$s\n" - - "\nPermission is hereby granted, free of charge, to any person obtaining a copy" - "of this software and associated documentation files (the "Software"), to deal" - "in the Software without restriction, including without limitation the rights" - "to use, copy, modify, merge, publish, distribute, sublicense, and/or sell" - "copies of the Software, and to permit persons to whom the Software is" - "furnished to do so, subject to the following conditions:\n" - - "\nThe above copyright notice and this permission notice shall be included in all" - "copies or substantial portions of the Software.\n" - - "\nTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR" - "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY," - "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE" - "AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER" - "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM," - "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE" - "SOFTWARE." - - - - "\nCopyright © %1$s %2$s\n" - - "\nThis program is free software: you can redistribute it and/or modify" - "it under the terms of the GNU General Public License as published by" - "the Free Software Foundation, either version 3 of the License, or" - "(at your option) any later version.\n" - - "\nThis program is distributed in the hope that it will be useful," - "but WITHOUT ANY WARRANTY; without even the implied warranty of" - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the" - "GNU General Public License for more details.\n" - - "\nYou should have received a copy of the GNU General Public License" - "along with this program. If not, see http://www.gnu.org/licenses.\n" - - - - "\nCopyright © %1$s %2$s\n" - - "\nRedistribution and use in source and binary forms, with or without" - "modification, are permitted provided that the following conditions are met:\n" - - "\n1. Redistributions of source code must retain the above copyright notice, this" - " list of conditions and the following disclaimer.\n" - "2. Redistributions in binary form must reproduce the above copyright notice," - " this list of conditions and the following disclaimer in the documentation" - " and/or other materials provided with the distribution.\n" - - "\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND" - "ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED" - "WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE" - "DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR" - "ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES" - "(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;" - "LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND" - "ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT" - "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS" - "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" - - "\nThe views and conclusions contained in the software and documentation are those" - "of the authors and should not be interpreted as representing official policies," - "either expressed or implied, of the FreeBSD Project.\n" - - diff --git a/material-about-library/src/main/res/values/styles.xml b/material-about-library/src/main/res/values/styles.xml deleted file mode 100644 index d0c6188b..00000000 --- a/material-about-library/src/main/res/values/styles.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index ef628913..955021f9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,7 +3,7 @@ include ':wear' include ':codegen' include ':annotation' rootProject.name='Szkolny.eu' -include ':app', ':agendacalendarview', ':mhttp', ':cafebar', ':szkolny-font', ':nachos' +include ':app', ':agendacalendarview', ':mhttp', ':szkolny-font', ':nachos' /* include ':Navigation' project(':Navigation').projectDir = new File(settingsDir, '../Navigation/navlib')*/ From 15f9db5ca6e10c6fa59815635909b27b547ce66d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 20 Mar 2021 20:11:50 +0100 Subject: [PATCH 006/113] [Gradle] Extract nachos dependency. --- app/build.gradle | 2 +- nachos/build.gradle | 23 - nachos/maven_push.gradle | 111 -- nachos/src/main/AndroidManifest.xml | 5 - .../hootsuite/nachos/ChipConfiguration.java | 78 -- .../com/hootsuite/nachos/NachoTextView.java | 1165 ----------------- .../java/com/hootsuite/nachos/chip/Chip.java | 30 - .../hootsuite/nachos/chip/ChipCreator.java | 44 - .../com/hootsuite/nachos/chip/ChipInfo.java | 20 - .../com/hootsuite/nachos/chip/ChipSpan.java | 511 -------- .../nachos/chip/ChipSpanChipCreator.java | 60 - .../terminator/ChipTerminatorHandler.java | 95 -- .../DefaultChipTerminatorHandler.java | 115 -- .../nachos/terminator/TextIterator.java | 63 - .../nachos/tokenizer/BaseChipTokenizer.java | 89 -- .../nachos/tokenizer/ChipTokenizer.java | 134 -- .../nachos/tokenizer/SpanChipTokenizer.java | 248 ---- .../validator/ChipifyingNachoValidator.java | 32 - .../validator/IllegalCharacterIdentifier.java | 5 - .../nachos/validator/NachoValidator.java | 30 - nachos/src/main/project.properties | 2 - .../res/color/chip_material_background.xml | 4 - nachos/src/main/res/values/attrs.xml | 12 - nachos/src/main/res/values/colors.xml | 5 - nachos/src/main/res/values/dimens.xml | 7 - nachos/src/main/res/values/strings.xml | 3 - nachos/src/main/res/values/styles.xml | 10 - settings.gradle | 2 +- 28 files changed, 2 insertions(+), 2903 deletions(-) delete mode 100644 nachos/build.gradle delete mode 100644 nachos/maven_push.gradle delete mode 100644 nachos/src/main/AndroidManifest.xml delete mode 100644 nachos/src/main/java/com/hootsuite/nachos/ChipConfiguration.java delete mode 100644 nachos/src/main/java/com/hootsuite/nachos/NachoTextView.java delete mode 100644 nachos/src/main/java/com/hootsuite/nachos/chip/Chip.java delete mode 100644 nachos/src/main/java/com/hootsuite/nachos/chip/ChipCreator.java delete mode 100644 nachos/src/main/java/com/hootsuite/nachos/chip/ChipInfo.java delete mode 100644 nachos/src/main/java/com/hootsuite/nachos/chip/ChipSpan.java delete mode 100644 nachos/src/main/java/com/hootsuite/nachos/chip/ChipSpanChipCreator.java delete mode 100644 nachos/src/main/java/com/hootsuite/nachos/terminator/ChipTerminatorHandler.java delete mode 100644 nachos/src/main/java/com/hootsuite/nachos/terminator/DefaultChipTerminatorHandler.java delete mode 100644 nachos/src/main/java/com/hootsuite/nachos/terminator/TextIterator.java delete mode 100644 nachos/src/main/java/com/hootsuite/nachos/tokenizer/BaseChipTokenizer.java delete mode 100644 nachos/src/main/java/com/hootsuite/nachos/tokenizer/ChipTokenizer.java delete mode 100644 nachos/src/main/java/com/hootsuite/nachos/tokenizer/SpanChipTokenizer.java delete mode 100644 nachos/src/main/java/com/hootsuite/nachos/validator/ChipifyingNachoValidator.java delete mode 100644 nachos/src/main/java/com/hootsuite/nachos/validator/IllegalCharacterIdentifier.java delete mode 100644 nachos/src/main/java/com/hootsuite/nachos/validator/NachoValidator.java delete mode 100644 nachos/src/main/project.properties delete mode 100644 nachos/src/main/res/color/chip_material_background.xml delete mode 100644 nachos/src/main/res/values/attrs.xml delete mode 100644 nachos/src/main/res/values/colors.xml delete mode 100644 nachos/src/main/res/values/dimens.xml delete mode 100644 nachos/src/main/res/values/strings.xml delete mode 100644 nachos/src/main/res/values/styles.xml diff --git a/app/build.gradle b/app/build.gradle index 56f5e4f4..2f2211d8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -171,7 +171,7 @@ dependencies { implementation "eu.szkolny:cafebar:5bf0c618de" implementation "eu.szkolny:material-about-library:0534abf316" implementation project(":mhttp") - implementation project(":nachos") + implementation "eu.szkolny:nachos:0e5dfcaceb" //implementation project(":Navigation") implementation project(":szkolny-font") diff --git a/nachos/build.gradle b/nachos/build.gradle deleted file mode 100644 index 821a4a83..00000000 --- a/nachos/build.gradle +++ /dev/null @@ -1,23 +0,0 @@ -apply plugin: 'com.android.library' - -android { - compileSdkVersion setup.compileSdk - - defaultConfig { - minSdkVersion 15 - targetSdkVersion setup.targetSdk - versionCode 1 - versionName "1.0" - } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - } -} - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation "com.android.support:support-compat:28.0.0" -} \ No newline at end of file diff --git a/nachos/maven_push.gradle b/nachos/maven_push.gradle deleted file mode 100644 index 946f7859..00000000 --- a/nachos/maven_push.gradle +++ /dev/null @@ -1,111 +0,0 @@ -apply plugin: 'maven' -apply plugin: 'signing' - -def isReleaseBuild() { - return VERSION_NAME.contains("SNAPSHOT") == false -} - -def getReleaseRepositoryUrl() { - return ARTIFACT_REPO -} - -def getSnapshotRepositoryUrl() { - return ARTIFACT_SNAPSHOT_REPO -} - -def getRepositoryUsername() { - return System.properties['username'] -} - -def getRepositoryPassword() { - return System.properties['password'] -} - -afterEvaluate { project -> - uploadArchives { - repositories { - mavenDeployer { - beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } - - pom.groupId = GROUP - pom.artifactId = POM_ARTIFACT_ID - pom.version = VERSION_NAME - - repository(url: getReleaseRepositoryUrl()) { - authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) - } - snapshotRepository(url: getSnapshotRepositoryUrl()) { - authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) - } - - pom.project { - name POM_NAME - packaging POM_PACKAGING - description POM_DESCRIPTION - url POM_URL - - scm { - url POM_SCM_URL - connection POM_SCM_CONNECTION - developerConnection POM_SCM_DEV_CONNECTION - } - - licenses { - license { - name POM_LICENCE_NAME - url POM_LICENCE_URL - distribution POM_LICENCE_DIST - } - } - - developers { - developer { - id POM_DEVELOPER_ID - name POM_DEVELOPER_NAME - } - } - } - } - } - } - - task installArchives(type: Upload) { - description "Installs the artifacts to the local Maven repository." - configuration = configurations['archives'] - repositories { - mavenDeployer { - pom.groupId = GROUP - pom.artifactId = POM_ARTIFACT_ID - pom.version = VERSION_NAME - - repository url: "file://${System.properties['user.home']}/.m2/repository" - } - } - } - - signing { - required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") } - sign configurations.archives - } - - task androidJavadocs(type: Javadoc) { - source = android.sourceSets.main.java.srcDirs - classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) - failOnError = false - } - - task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) { - classifier = 'javadoc' - from androidJavadocs.destinationDir - } - - task androidSourcesJar(type: Jar) { - classifier = 'sources' - from android.sourceSets.main.java.srcDirs - } - - artifacts { - archives androidSourcesJar - archives androidJavadocsJar - } -} \ No newline at end of file diff --git a/nachos/src/main/AndroidManifest.xml b/nachos/src/main/AndroidManifest.xml deleted file mode 100644 index ad3cc65f..00000000 --- a/nachos/src/main/AndroidManifest.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/nachos/src/main/java/com/hootsuite/nachos/ChipConfiguration.java b/nachos/src/main/java/com/hootsuite/nachos/ChipConfiguration.java deleted file mode 100644 index 0b8fb3b7..00000000 --- a/nachos/src/main/java/com/hootsuite/nachos/ChipConfiguration.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.hootsuite.nachos; - -import android.content.res.ColorStateList; - -public class ChipConfiguration { - - private final int mChipHorizontalSpacing; - private final ColorStateList mChipBackground; - private final int mChipCornerRadius; - private final int mChipTextColor; - private final int mChipTextSize; - private final int mChipHeight; - private final int mChipVerticalSpacing; - private final int mMaxAvailableWidth; - - /** - * Creates a new ChipConfiguration. You can pass in {@code -1} or {@code null} for any of the parameters to indicate that parameter should be - * ignored. - * - * @param chipHorizontalSpacing the amount of horizontal space (in pixels) to put between consecutive chips - * @param chipBackground the {@link ColorStateList} to set as the background of the chips - * @param chipCornerRadius the corner radius of the chip background, in pixels - * @param chipTextColor the color to set as the text color of the chips - * @param chipTextSize the font size (in pixels) to use for the text of the chips - * @param chipHeight the height (in pixels) of each chip - * @param chipVerticalSpacing the amount of vertical space (in pixels) to put between chips on consecutive lines - * @param maxAvailableWidth the maximum available with for a chip (the width of a full line of text in the text view) - */ - ChipConfiguration(int chipHorizontalSpacing, - ColorStateList chipBackground, - int chipCornerRadius, - int chipTextColor, - int chipTextSize, - int chipHeight, - int chipVerticalSpacing, - int maxAvailableWidth) { - mChipHorizontalSpacing = chipHorizontalSpacing; - mChipBackground = chipBackground; - mChipCornerRadius = chipCornerRadius; - mChipTextColor = chipTextColor; - mChipTextSize = chipTextSize; - mChipHeight = chipHeight; - mChipVerticalSpacing = chipVerticalSpacing; - mMaxAvailableWidth = maxAvailableWidth; - } - - public int getChipHorizontalSpacing() { - return mChipHorizontalSpacing; - } - - public ColorStateList getChipBackground() { - return mChipBackground; - } - - public int getChipCornerRadius() { - return mChipCornerRadius; - } - - public int getChipTextColor() { - return mChipTextColor; - } - - public int getChipTextSize() { - return mChipTextSize; - } - - public int getChipHeight() { - return mChipHeight; - } - - public int getChipVerticalSpacing() { - return mChipVerticalSpacing; - } - - public int getMaxAvailableWidth() { - return mMaxAvailableWidth; - } -} diff --git a/nachos/src/main/java/com/hootsuite/nachos/NachoTextView.java b/nachos/src/main/java/com/hootsuite/nachos/NachoTextView.java deleted file mode 100644 index b2cb81ab..00000000 --- a/nachos/src/main/java/com/hootsuite/nachos/NachoTextView.java +++ /dev/null @@ -1,1165 +0,0 @@ -package com.hootsuite.nachos; - -import android.content.ClipData; -import android.content.ClipboardManager; -import android.content.Context; -import android.content.res.ColorStateList; -import android.content.res.TypedArray; -import android.graphics.Color; -import android.graphics.Paint; -import android.text.Editable; -import android.text.Layout; -import android.text.TextUtils; -import android.text.TextWatcher; -import android.util.AttributeSet; -import android.util.Log; -import android.util.Pair; -import android.view.GestureDetector; -import android.view.MotionEvent; -import android.view.View; -import android.view.inputmethod.EditorInfo; -import android.widget.Adapter; -import android.widget.AdapterView; -import android.widget.AutoCompleteTextView; -import android.widget.ListAdapter; -import android.widget.MultiAutoCompleteTextView; - -import androidx.annotation.ColorInt; -import androidx.annotation.ColorRes; -import androidx.annotation.DimenRes; -import androidx.annotation.Dimension; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.content.ContextCompat; - -import com.hootsuite.nachos.chip.Chip; -import com.hootsuite.nachos.chip.ChipInfo; -import com.hootsuite.nachos.chip.ChipSpan; -import com.hootsuite.nachos.chip.ChipSpanChipCreator; -import com.hootsuite.nachos.terminator.ChipTerminatorHandler; -import com.hootsuite.nachos.terminator.DefaultChipTerminatorHandler; -import com.hootsuite.nachos.tokenizer.ChipTokenizer; -import com.hootsuite.nachos.tokenizer.SpanChipTokenizer; -import com.hootsuite.nachos.validator.ChipifyingNachoValidator; -import com.hootsuite.nachos.validator.IllegalCharacterIdentifier; -import com.hootsuite.nachos.validator.NachoValidator; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -/** - * An editable TextView extending {@link MultiAutoCompleteTextView} that supports "chipifying" pieces of text and displaying suggestions for segments of the text. - *

The ChipTokenizer

- * To customize chipifying with this class you can provide a custom {@link ChipTokenizer} by calling {@link #setChipTokenizer(ChipTokenizer)}. - * By default the {@link SpanChipTokenizer} is used. - *

Chip Terminators

- * To set which characters trigger the creation of a chip, call {@link #addChipTerminator(char, int)} or {@link #setChipTerminators(Map)}. - * For example if tapping enter should cause all unchipped text to become chipped, call - * {@code chipSuggestionTextView.addChipTerminator('\n', ChipTerminatorHandler.BEHAVIOR_CHIPIFY_ALL);} - * To completely customize how chips are created when text is entered in this text view you can provide a custom {@link ChipTerminatorHandler} - * through {@link #setChipTerminatorHandler(ChipTerminatorHandler)} - *

Illegal Characters

- * To prevent a character from being typed you can call {@link #setIllegalCharacterIdentifier(IllegalCharacterIdentifier)}} to identify characters - * that should be considered illegal. - *

Suggestions

- * To provide suggestions you must provide an {@link android.widget.Adapter} by calling {@link #setAdapter(ListAdapter)} - *

UI Customization

- * This view defines six custom attributes (all of which are optional): - *
    - *
  • chipHorizontalSpacing - the horizontal space between chips
  • - *
  • chipBackground - the background color of the chip
  • - *
  • chipCornerRadius - the corner radius of the chip background
  • - *
  • chipTextColor - the color of the chip text
  • - *
  • chipTextSize - the font size of the chip text
  • - *
  • chipHeight - the height of a single chip
  • - *
  • chipVerticalSpacing - the vertical space between chips on consecutive lines - *
      - *
    • Note: chipVerticalSpacing is only used if a chipHeight is also set
    • - *
    - *
  • - *
- * The values of these attributes will be passed to the ChipTokenizer through {@link ChipTokenizer#applyConfiguration(Editable, ChipConfiguration)} - *

Validation

- * This class can perform validation when certain events occur (such as losing focus). When the validation occurs is decided by - * {@link AutoCompleteTextView}. To perform validation, set a {@link NachoValidator}: - *
- *         nachoTextView.setNachoValidator(new ChipifyingNachoValidator());
- *     
- * Note: The NachoValidator will be ignored if a ChipTokenizer is not set. To perform validation without a ChipTokenizer you can use - * {@link AutoCompleteTextView}'s built-in {@link AutoCompleteTextView.Validator Validator} through {@link #setValidator(Validator)} - *

Editing Chips

- * This class also supports editing chips on touch. To enable this behavior call {@link #enableEditChipOnTouch(boolean, boolean)}. To disable this - * behavior you can call {@link #disableEditChipOnTouch()} - *

Example Setup:

- * A standard setup for this class could look something like the following: - *
- *         String[] suggestions = new String[]{"suggestion 1", "suggestion 2"};
- *         ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_dropdown_item_1line, suggestions);
- *         nachoTextView.setAdapter(adapter);
- *         nachoTextView.addChipTerminator('\n', ChipTerminatorHandler.BEHAVIOR_CHIPIFY_ALL);
- *         nachoTextView.addChipTerminator(' ', ChipTerminatorHandler.BEHAVIOR_CHIPIFY_TO_TERMINATOR);
- *         nachoTextView.setIllegalCharacters('@');
- *         nachoTextView.setNachoValidator(new ChipifyingNachoValidator());
- *         nachoTextView.enableEditChipOnTouch(true, true);
- *         nachoTextView.setOnChipClickListener(new NachoTextView.OnChipClickListener() {
- *            {@literal @Override}
- *             public void onChipClick(Chip chip, MotionEvent motionEvent) {
- *                 // Handle click event
- *             }
- *         });
- *         nachoTextView.setOnChipRemoveListener(new NachoTextView.OnChipRemoveListener() {
- *            {@literal @Override}
- *             public void onChipRemove(Chip chip) {
- *                 // Handle remove event
- *             }
- *         });
- *     
- * - * @see SpanChipTokenizer - * @see DefaultChipTerminatorHandler - * @see ChipifyingNachoValidator - */ -public class NachoTextView extends MultiAutoCompleteTextView implements TextWatcher, AdapterView.OnItemClickListener { - - // UI Attributes - private int mChipHorizontalSpacing = -1; - private ColorStateList mChipBackground = null; - private int mChipCornerRadius = -1; - private int mChipTextColor = Color.TRANSPARENT; - private int mChipTextSize = -1; - private int mChipHeight = -1; - private int mChipVerticalSpacing = -1; - - private int mDefaultPaddingTop = 0; - private int mDefaultPaddingBottom = 0; - /** - * Flag to keep track of the padding state so we only update the padding when necessary - */ - private boolean mUsingDefaultPadding = true; - - // Touch events - @Nullable - private OnChipClickListener mOnChipClickListener; - private GestureDetector singleTapDetector; - private boolean mEditChipOnTouchEnabled; - private boolean mMoveChipToEndOnEdit; - private boolean mChipifyUnterminatedTokensOnEdit; - - // Text entry - @Nullable - private ChipTokenizer mChipTokenizer; - @Nullable - private ChipTerminatorHandler mChipTerminatorHandler; - @Nullable - private NachoValidator mNachoValidator; - @Nullable - private IllegalCharacterIdentifier illegalCharacterIdentifier; - - @Nullable - private OnChipRemoveListener mOnChipRemoveListener; - private List mChipsToRemove = new ArrayList<>(); - private boolean mIgnoreTextChangedEvents; - private int mTextChangedStart; - private int mTextChangedEnd; - private boolean mIsPasteEvent; - - // Measurement - private boolean mMeasured; - - // Layout - private boolean mLayoutComplete; - - public NachoTextView(Context context) { - super(context); - init(null); - } - - public NachoTextView(Context context, AttributeSet attrs) { - super(context, attrs); - init(attrs); - } - - public NachoTextView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(attrs); - } - - private void init(@Nullable AttributeSet attrs) { - Context context = getContext(); - - if (attrs != null) { - TypedArray attributes = context.getTheme().obtainStyledAttributes( - attrs, - R.styleable.NachoTextView, - 0, - R.style.DefaultChipSuggestionTextView); - - try { - mChipHorizontalSpacing = attributes.getDimensionPixelSize(R.styleable.NachoTextView_chipHorizontalSpacing, -1); - mChipBackground = attributes.getColorStateList(R.styleable.NachoTextView_chipBackground); - mChipCornerRadius = attributes.getDimensionPixelSize(R.styleable.NachoTextView_chipCornerRadius, -1); - mChipTextColor = attributes.getColor(R.styleable.NachoTextView_chipTextColor, Color.TRANSPARENT); - mChipTextSize = attributes.getDimensionPixelSize(R.styleable.NachoTextView_chipTextSize, -1); - mChipHeight = attributes.getDimensionPixelSize(R.styleable.NachoTextView_chipHeight, -1); - mChipVerticalSpacing = attributes.getDimensionPixelSize(R.styleable.NachoTextView_chipVerticalSpacing, -1); - } finally { - attributes.recycle(); - } - } - - mDefaultPaddingTop = getPaddingTop(); - mDefaultPaddingBottom = getPaddingBottom(); - - singleTapDetector = new GestureDetector(getContext(), new SingleTapListener()); - - setImeOptions(EditorInfo.IME_FLAG_NO_FULLSCREEN); - addTextChangedListener(this); - setChipTokenizer(new SpanChipTokenizer<>(context, new ChipSpanChipCreator(), ChipSpan.class)); - setChipTerminatorHandler(new DefaultChipTerminatorHandler()); - setOnItemClickListener(this); - - updatePadding(); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - - if (!mMeasured && getWidth() > 0) { - // Refresh the tokenizer for width changes - invalidateChips(); - mMeasured = true; - } - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - - if (!mLayoutComplete) { - invalidateChips(); - mLayoutComplete = true; - } - } - - /** - * Updates the padding based on whether or not any chips are present to avoid the view from changing heights when chips are inserted/deleted. - * Extra padding is added when there are no chips. When there are chips the padding is reverted to its defaults. This only affects top and bottom - * padding because the chips only affect the height of the view. - */ - private void updatePadding() { - if (mChipHeight != -1) { - boolean chipsArePresent = !getAllChips().isEmpty(); - if (!chipsArePresent && mUsingDefaultPadding) { - mUsingDefaultPadding = false; - Paint paint = getPaint(); - Paint.FontMetricsInt fm = paint.getFontMetricsInt(); - int textHeight = fm.descent - fm.ascent; - // Calculate how tall the view should be if there were chips - int newTextHeight = mChipHeight + (mChipVerticalSpacing != -1 ? mChipVerticalSpacing : 0); - // We need to add half our missing height above and below the text by increasing top and bottom padding - int paddingAdjustment = (newTextHeight - textHeight) / 2; - super.setPadding(getPaddingLeft(), mDefaultPaddingTop + paddingAdjustment, getPaddingRight(), mDefaultPaddingBottom + paddingAdjustment); - } else if (chipsArePresent && !mUsingDefaultPadding) { - // If there are chips we can revert to default padding - mUsingDefaultPadding = true; - super.setPadding(getPaddingLeft(), mDefaultPaddingTop, getPaddingRight(), mDefaultPaddingBottom); - } - } - } - - /** - * Sets the padding on this View. The left and right padding will be handled as they normally would in a TextView. The top and bottom padding passed - * here will be the padding that is used when there are one or more chips in the text view. When there are no chips present, the padding will be - * increased to make sure the overall height of the text view stays the same, since chips take up more vertical space than plain text. - * - * @param left the left padding in pixels - * @param top the top padding in pixels - * @param right the right padding in pixels - * @param bottom the bottom padding in pixels - */ - @Override - public void setPadding(int left, int top, int right, int bottom) { - // Call the super method so that left and right padding are updated - // top and bottom padding will be handled in updatePadding() - super.setPadding(left, top, right, bottom); - mDefaultPaddingTop = top; - mDefaultPaddingBottom = bottom; - updatePadding(); - } - - public int getChipHorizontalSpacing() { - return mChipHorizontalSpacing; - } - - public void setChipHorizontalSpacing(@DimenRes int chipHorizontalSpacingResId) { - mChipHorizontalSpacing = getContext().getResources().getDimensionPixelSize(chipHorizontalSpacingResId); - invalidateChips(); - } - - public ColorStateList getChipBackground() { - return mChipBackground; - } - - public void setChipBackgroundResource(@ColorRes int chipBackgroundResId) { - setChipBackground(ContextCompat.getColorStateList(getContext(), chipBackgroundResId)); - } - - public void setChipBackground(ColorStateList chipBackground) { - mChipBackground = chipBackground; - invalidateChips(); - } - - /** - * @return The chip background corner radius value, in pixels. - */ - @Dimension - public int getChipCornerRadius() { - return mChipCornerRadius; - } - - /** - * Sets the chip background corner radius. - * - * @param chipCornerRadiusResId The dimension resource with the corner radius value. - */ - public void setChipCornerRadiusResource(@DimenRes int chipCornerRadiusResId) { - setChipCornerRadius(getContext().getResources().getDimensionPixelSize(chipCornerRadiusResId)); - } - - /** - * Sets the chip background corner radius. - * - * @param chipCornerRadius The corner radius value, in pixels. - */ - public void setChipCornerRadius(@Dimension int chipCornerRadius) { - mChipCornerRadius = chipCornerRadius; - invalidateChips(); - } - - - public int getChipTextColor() { - return mChipTextColor; - } - - public void setChipTextColorResource(@ColorRes int chipTextColorResId) { - setChipTextColor(ContextCompat.getColor(getContext(), chipTextColorResId)); - } - - public void setChipTextColor(@ColorInt int chipTextColor) { - mChipTextColor = chipTextColor; - invalidateChips(); - } - - public int getChipTextSize() { - return mChipTextSize; - } - - public void setChipTextSize(@DimenRes int chipTextSizeResId) { - mChipTextSize = getContext().getResources().getDimensionPixelSize(chipTextSizeResId); - invalidateChips(); - } - - public int getChipHeight() { - return mChipHeight; - } - - public void setChipHeight(@DimenRes int chipHeightResId) { - mChipHeight = getContext().getResources().getDimensionPixelSize(chipHeightResId); - invalidateChips(); - } - - public int getChipVerticalSpacing() { - return mChipVerticalSpacing; - } - - public void setChipVerticalSpacing(@DimenRes int chipVerticalSpacingResId) { - mChipVerticalSpacing = getContext().getResources().getDimensionPixelSize(chipVerticalSpacingResId); - invalidateChips(); - } - - @Nullable - public ChipTokenizer getChipTokenizer() { - return mChipTokenizer; - } - - /** - * Sets the {@link ChipTokenizer} to be used by this ChipSuggestionTextView. - * Note that a Tokenizer set here will override any Tokenizer set by {@link #setTokenizer(Tokenizer)} - * - * @param chipTokenizer the {@link ChipTokenizer} to set - */ - public void setChipTokenizer(@Nullable ChipTokenizer chipTokenizer) { - mChipTokenizer = chipTokenizer; - if (mChipTokenizer != null) { - setTokenizer(new ChipTokenizerWrapper(mChipTokenizer)); - } else { - setTokenizer(null); - } - invalidateChips(); - } - - public void setOnChipClickListener(@Nullable OnChipClickListener onChipClickListener) { - mOnChipClickListener = onChipClickListener; - } - - public void setOnChipRemoveListener(@Nullable OnChipRemoveListener onChipRemoveListener) { - mOnChipRemoveListener = onChipRemoveListener; - } - - public void setChipTerminatorHandler(@Nullable ChipTerminatorHandler chipTerminatorHandler) { - mChipTerminatorHandler = chipTerminatorHandler; - } - - public void setNachoValidator(@Nullable NachoValidator nachoValidator) { - mNachoValidator = nachoValidator; - } - - /** - * @see ChipTerminatorHandler#setChipTerminators(Map) - */ - public void setChipTerminators(@Nullable Map chipTerminators) { - if (mChipTerminatorHandler != null) { - mChipTerminatorHandler.setChipTerminators(chipTerminators); - } - } - - /** - * @see ChipTerminatorHandler#addChipTerminator(char, int) - */ - public void addChipTerminator(char character, int behavior) { - if (mChipTerminatorHandler != null) { - mChipTerminatorHandler.addChipTerminator(character, behavior); - } - } - - /** - * @see ChipTerminatorHandler#setPasteBehavior(int) - */ - public void setPasteBehavior(int pasteBehavior) { - if (mChipTerminatorHandler != null) { - mChipTerminatorHandler.setPasteBehavior(pasteBehavior); - } - } - - /** - * Sets the {@link IllegalCharacterIdentifier} that will identify characters that should - * not show up in the field when typed (i.e. they will be deleted as soon as they are entered). - * If a character is listed as both a chip terminator character and an illegal character, - * it will be treated as an illegal character. - * - * @param illegalCharacterIdentifier the identifier to use - */ - public void setIllegalCharacterIdentifier(@Nullable IllegalCharacterIdentifier illegalCharacterIdentifier) { - this.illegalCharacterIdentifier = illegalCharacterIdentifier; - } - - /** - * Applies any updated configuration parameters to any existing chips and all future chips in the text view. - * - * @see ChipTokenizer#applyConfiguration(Editable, ChipConfiguration) - */ - public void invalidateChips() { - beginUnwatchedTextChange(); - - if (mChipTokenizer != null) { - Editable text = getText(); - int availableWidth = getWidth() - getCompoundPaddingLeft() - getCompoundPaddingRight(); - ChipConfiguration configuration = new ChipConfiguration( - mChipHorizontalSpacing, - mChipBackground, - mChipCornerRadius, - mChipTextColor, - mChipTextSize, - mChipHeight, - mChipVerticalSpacing, - availableWidth); - - mChipTokenizer.applyConfiguration(text, configuration); - } - - endUnwatchedTextChange(); - } - - /** - * Enables editing chips on touch events. When a touch event occurs, the touched chip will be put in editing mode. To later disable this behavior - * call {@link #disableEditChipOnTouch()}. - *

- * Note: If an {@link OnChipClickListener} is set it's behavior will override the behavior described here if it's - * {@link OnChipClickListener#onChipClick(Chip, MotionEvent)} method returns true. If that method returns false, the touched chip will be put - * in editing mode as expected. - *

- * - * @param moveChipToEnd if true, the chip will also be moved to the end of the text when it is put in editing mode - * @param chipifyUnterminatedTokens if true, all unterminated tokens will be chipified before the touched chip is put in editing mode - * @see #disableEditChipOnTouch() - */ - public void enableEditChipOnTouch(boolean moveChipToEnd, boolean chipifyUnterminatedTokens) { - mEditChipOnTouchEnabled = true; - mMoveChipToEndOnEdit = moveChipToEnd; - mChipifyUnterminatedTokensOnEdit = chipifyUnterminatedTokens; - } - - /** - * Disables editing chips on touch events. To re-enable this behavior call {@link #enableEditChipOnTouch(boolean, boolean)}. - * - * @see #enableEditChipOnTouch(boolean, boolean) - */ - public void disableEditChipOnTouch() { - mEditChipOnTouchEnabled = false; - } - - /** - * Puts the provided Chip in editing mode (i.e. reverts it to an unchipified token whose text can be edited). - * - * @param chip the chip to edit - * @param moveChipToEnd if true, the chip will also be moved to the end of the text - */ - public void setEditingChip(Chip chip, boolean moveChipToEnd) { - if (mChipTokenizer == null) { - return; - } - - beginUnwatchedTextChange(); - - Editable text = getText(); - if (moveChipToEnd) { - // Move the chip text to the end of the text - text.append(chip.getText()); - // Delete the existing chip - mChipTokenizer.deleteChipAndPadding(chip, text); - // Move the cursor to the end of the text - setSelection(text.length()); - } else { - int chipStart = mChipTokenizer.findChipStart(chip, text); - mChipTokenizer.revertChipToToken(chip, text); - setSelection(mChipTokenizer.findTokenEnd(text, chipStart)); - } - - endUnwatchedTextChange(); - } - - @Override - public boolean onTouchEvent(@NonNull MotionEvent event) { - boolean wasHandled = false; - clearChipStates(); - Chip touchedChip = findTouchedChip(event); - if (touchedChip != null && isFocused() && singleTapDetector.onTouchEvent(event)) { - touchedChip.setState(View.PRESSED_SELECTED_STATE_SET); - if (onChipClicked(touchedChip)) { - wasHandled = true; - } - if (mOnChipClickListener != null) { - mOnChipClickListener.onChipClick(touchedChip, event); - } - } - - // Getting NullPointerException inside Editor.updateFloatingToolbarVisibility (Editor.java:1520) - // primarily seen in Samsung Nougat devices. - boolean superOnTouch = false; - try { - superOnTouch = super.onTouchEvent(event); - } catch (NullPointerException e) { - Log.w("Nacho", String.format("Error during touch event of type [%d]", event.getAction()), e); - // can't handle or reproduce, but will monitor the error - } - - return wasHandled || superOnTouch; - } - - @Nullable - private Chip findTouchedChip(MotionEvent event) { - if (mChipTokenizer == null) { - return null; - } - - Editable text = getText(); - int offset = getOffsetForPosition(event.getX(), event.getY()); - List chips = getAllChips(); - for (Chip chip : chips) { - int chipStart = mChipTokenizer.findChipStart(chip, text); - int chipEnd = mChipTokenizer.findChipEnd(chip, text); // This is actually the index of the character just past the end of the chip - // When a touch event occurs getOffsetForPosition will either return the index of the first character of the span or the index of the - // character one past the end of the span - // This matches up perfectly with chipStart and chipEnd so we can just directly compare them... - if (chipStart <= offset && offset <= chipEnd) { - float startX = getXForIndex(chipStart); - float endX = getXForIndex(chipEnd - 1); - float eventX = event.getX(); - // ... however, when comparing the x coordinate we need to use (chipEnd - 1) because chipEnd will give us the x coordinate of the - // beginning of the next span since that is actually what chipEnd holds. We want the x coordinate of the end of the current span so - // we use (chipEnd - 1) - if (startX <= eventX && eventX <= endX) { - return chip; - } - } - } - return null; - } - - /** - * Implement this method to handle chip clicked events. - * - * @param chip the chip that was clicked - * @return true if the event was handled, otherwise false - */ - public boolean onChipClicked(Chip chip) { - boolean wasHandled = false; - if (mEditChipOnTouchEnabled) { - if (mChipifyUnterminatedTokensOnEdit) { - chipifyAllUnterminatedTokens(); - } - setEditingChip(chip, mMoveChipToEndOnEdit); - wasHandled = true; - } - return wasHandled; - } - - private float getXForIndex(int index) { - Layout layout = getLayout(); - return layout.getPrimaryHorizontal(index); - } - - private void clearChipStates() { - for (Chip chip : getAllChips()) { - chip.setState(View.EMPTY_STATE_SET); - } - } - - @Override - public boolean onTextContextMenuItem(int id) { - int start = getSelectionStart(); - int end = getSelectionEnd(); - switch (id) { - case android.R.id.cut: - try { - setClipboardData(ClipData.newPlainText(null, getTextWithPlainTextSpans(start, end))); - } catch (StringIndexOutOfBoundsException e) { - throw new StringIndexOutOfBoundsException( - String.format( - "%s \nError cutting text index [%s, %s] for text [%s] and substring [%s]", - e.getMessage(), - start, - end, - getText().toString(), - getText().subSequence(start, end))); - } - getText().delete(getSelectionStart(), getSelectionEnd()); - return true; - case android.R.id.copy: - try { - setClipboardData(ClipData.newPlainText(null, getTextWithPlainTextSpans(start, end))); - } catch (StringIndexOutOfBoundsException e) { - throw new StringIndexOutOfBoundsException( - String.format( - "%s \nError copying text index [%s, %s] for text [%s] and substring [%s]", - e.getMessage(), - start, - end, - getText().toString(), - getText().subSequence(start, end))); - } - return true; - case android.R.id.paste: - mIsPasteEvent = true; - boolean returnValue = super.onTextContextMenuItem(id); - mIsPasteEvent = false; - return returnValue; - default: - return super.onTextContextMenuItem(id); - } - } - - private void setClipboardData(ClipData clip) { - ClipboardManager clipboard = (ClipboardManager) getContext(). - getSystemService(Context.CLIPBOARD_SERVICE); - clipboard.setPrimaryClip(clip); - } - - /** - * If a {@link android.widget.AutoCompleteTextView.Validator Validator} was set, this method will validate the entire text. - * (Overrides the superclass method which only validates the current token) - */ - @Override - public void performValidation() { - if (mNachoValidator == null || mChipTokenizer == null) { - super.performValidation(); - return; - } - - CharSequence text = getText(); - if (!TextUtils.isEmpty(text) && !mNachoValidator.isValid(mChipTokenizer, text)) { - setRawText(mNachoValidator.fixText(mChipTokenizer, text)); - } - } - - /** - * From the point this method is called to when {@link #endUnwatchedTextChange()} is called, all TextChanged events will be ignored - */ - private void beginUnwatchedTextChange() { - mIgnoreTextChangedEvents = true; - } - - /** - * After this method is called TextChanged events will resume being handled. - * This method also calls {@link #updatePadding()} in case the unwatched changed created/destroyed chips - */ - private void endUnwatchedTextChange() { - updatePadding(); - mIgnoreTextChangedEvents = false; - } - - /** - * Sets the contents of this text view without performing any processing (nothing will be chipified, no characters will be removed etc.) - * - * @param text the text to set - */ - private void setRawText(CharSequence text) { - beginUnwatchedTextChange(); - super.setText(text); - endUnwatchedTextChange(); - } - - /** - * Sets the contents of this text view to contain the provided list of strings. The text view will be cleared then each string in the list will - * be chipified and appended to the text. - * - * @param chipValues the list of strings to chipify and set as the contents of the text view or null to clear the text view - */ - public void setText(@Nullable List chipValues) { - if (mChipTokenizer == null) { - return; - } - beginUnwatchedTextChange(); - - Editable text = getText(); - text.clear(); - - if (chipValues != null) { - for (String chipValue : chipValues) { - CharSequence chippedText = mChipTokenizer.terminateToken(chipValue, null); - text.append(chippedText); - } - } - setSelection(text.length()); - - endUnwatchedTextChange(); - } - - public void setTextWithChips(@Nullable List chips) { - if (mChipTokenizer == null) { - return; - } - beginUnwatchedTextChange(); - - Editable text = getText(); - text.clear(); - - if (chips != null) { - for (ChipInfo chipInfo : chips) { - CharSequence chippedText = mChipTokenizer.terminateToken(chipInfo.getText(), chipInfo.getData()); - text.append(chippedText); - } - } - setSelection(text.length()); - endUnwatchedTextChange(); - } - - public void addTextWithChips(@Nullable List chips) { - if (mChipTokenizer == null) { - return; - } - beginUnwatchedTextChange(); - - Editable text = getText(); - - if (chips != null) { - for (ChipInfo chipInfo : chips) { - CharSequence chippedText = mChipTokenizer.terminateToken(chipInfo.getText(), chipInfo.getData()); - text.append(chippedText); - } - } - setSelection(text.length()); - endUnwatchedTextChange(); - } - - @Override - public void onItemClick(AdapterView adapterView, View view, int position, long id) { - if (mChipTokenizer == null) { - return; - } - Adapter adapter = getAdapter(); - if (adapter == null) { - return; - } - beginUnwatchedTextChange(); - - Object data = getDataForSuggestion(adapter, position); - CharSequence text = getFilter().convertResultToString(adapter.getItem(position)); - - clearComposingText(); - int end = getSelectionEnd(); - Editable editable = getText(); - int start = mChipTokenizer.findTokenStart(editable, end); - - // guard against java.lang.StringIndexOutOfBoundsException - start = Math.min(Math.max(0, start), editable.length()); - end = Math.min(Math.max(0, end), editable.length()); - if (end < start) { - end = start; - } - - editable.replace(start, end, mChipTokenizer.terminateToken(text, data)); - - endUnwatchedTextChange(); - } - - /** - * Returns a object that will be associated with a chip that is about to be created for the item at {@code position} in {@code adapter} because that - * item was just tapped. - * - * @param adapter the adapter supplying the suggestions - * @param position the position of the suggestion that was tapped - * @return the data object - */ - protected Object getDataForSuggestion(@NonNull Adapter adapter, int position) { - return adapter.getItem(position); - } - - /** - * If there is a ChipTokenizer set, this method will do nothing. Instead we wait until the OnItemClickListener is triggered to actually perform - * the text replacement so we can also associate the suggestion data with it. - *

- * If there is no ChipTokenizer set, we call through to the super method. - * - * @param text the text to be chipified - */ - @Override - protected void replaceText(CharSequence text) { - // If we have a ChipTokenizer, this will be handled by our OnItemClickListener so we can do nothing here. - // If we don't have a ChipTokenizer, we'll use the default behavior - if (mChipTokenizer == null) { - super.replaceText(text); - } - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - if (mIgnoreTextChangedEvents) { - return; - } - - mTextChangedStart = start; - mTextChangedEnd = start + after; - - // Check for backspace - if (mChipTokenizer != null) { - if (count > 0 && after < count) { - int end = start + count; - Editable message = getText(); - Chip[] chips = mChipTokenizer.findAllChips(start, end, message); - - for (Chip chip : chips) { - int spanStart = mChipTokenizer.findChipStart(chip, message); - int spanEnd = mChipTokenizer.findChipEnd(chip, message); - if ((spanStart < end) && (spanEnd > start)) { - // Add to remove list - mChipsToRemove.add(chip); - } - } - } - } - } - - @Override - public void onTextChanged(@NonNull CharSequence textChanged, int start, int before, int count) { - } - - @Override - public void afterTextChanged(Editable message) { - if (mIgnoreTextChangedEvents) { - return; - } - - // Avoid triggering text changed events from changes we make in this method - beginUnwatchedTextChange(); - - // Handle backspace key - if (mChipTokenizer != null) { - Iterator iterator = mChipsToRemove.iterator(); - while (iterator.hasNext()) { - Chip chip = iterator.next(); - iterator.remove(); - mChipTokenizer.deleteChip(chip, message); - if (mOnChipRemoveListener != null) { - mOnChipRemoveListener.onChipRemove(chip); - } - } - } - - // Handle an illegal or chip terminator character - if (message.length() >= mTextChangedEnd && message.length() >= mTextChangedStart) { - handleTextChanged(mTextChangedStart, mTextChangedEnd); - } - - endUnwatchedTextChange(); - } - - private void handleTextChanged(int start, int end) { - if (start == end) { - // If start and end are the same there was text deleted, so this type of event can be ignored - return; - } - - // First remove any illegal characters - Editable text = getText(); - CharSequence subText = text.subSequence(start, end); - CharSequence withoutIllegalCharacters = removeIllegalCharacters(subText); - - // Check if illegal characters were found - if (withoutIllegalCharacters.length() < subText.length()) { - text.replace(start, end, withoutIllegalCharacters); - end = start + withoutIllegalCharacters.length(); - clearComposingText(); - } - - if (start == end) { - // If start and end are the same here, it means only illegal characters were inserted so there's nothing left to do - return; - } - - // Then handle chip terminator characters - if (mChipTokenizer != null && mChipTerminatorHandler != null) { - int newSelectionIndex = mChipTerminatorHandler.findAndHandleChipTerminators(mChipTokenizer, getText(), start, end, mIsPasteEvent); - if (newSelectionIndex > 0) { - setSelection(newSelectionIndex); - } - } - } - - private CharSequence removeIllegalCharacters(CharSequence text) { - StringBuilder newText = new StringBuilder(); - - for (int i = 0; i < text.length(); i++) { - char theChar = text.charAt(i); - if (!isIllegalCharacter(theChar)) { - newText.append(theChar); - } - } - - return newText; - } - - private boolean isIllegalCharacter(char character) { - if (illegalCharacterIdentifier != null) { - return illegalCharacterIdentifier.isCharacterIllegal(character); - } - return false; - } - - /** - * Chipifies all existing plain text in the field - */ - public void chipifyAllUnterminatedTokens() { - beginUnwatchedTextChange(); - chipifyAllUnterminatedTokens(getText()); - endUnwatchedTextChange(); - } - - private void chipifyAllUnterminatedTokens(Editable text) { - if (mChipTokenizer != null) { - mChipTokenizer.terminateAllTokens(text); - } - } - - /** - * Replaces the text from start (inclusive) to end (exclusive) with a chip - * containing the same text - * - * @param start the index of the first character to replace - * @param end one more than the index of the last character to replace - */ - public void chipify(int start, int end) { - beginUnwatchedTextChange(); - chipify(start, end, getText(), null); - endUnwatchedTextChange(); - } - - private void chipify(int start, int end, Editable text, Object data) { - if (mChipTokenizer != null) { - CharSequence textToChip = text.subSequence(start, end); - CharSequence chippedText = mChipTokenizer.terminateToken(textToChip, data); - text.replace(start, end, chippedText); - } - } - - private CharSequence getTextWithPlainTextSpans(int start, int end) { - Editable editable = getText(); - String selectedText = editable.subSequence(start, end).toString(); - - if (mChipTokenizer != null) { - List chips = Arrays.asList(mChipTokenizer.findAllChips(start, end, editable)); - Collections.reverse(chips); - for (Chip chip : chips) { - String chipText = chip.getText().toString(); - int chipStart = mChipTokenizer.findChipStart(chip, editable) - start; - int chipEnd = mChipTokenizer.findChipEnd(chip, editable) - start; - selectedText = selectedText.substring(0, chipStart) + chipText + selectedText.substring(chipEnd, selectedText.length()); - } - } - return selectedText; - } - - /** - * @return all of the chips currently in the text view - this does not include any unchipped text - */ - @NonNull - public List getAllChips() { - Editable text = getText(); - return mChipTokenizer != null ? Arrays.asList(mChipTokenizer.findAllChips(0, text.length(), text)) : new ArrayList(); - } - - /** - * Returns a List of the string values of all the chips in the text (obtained through {@link Chip#getText()}). - * This does not include the text of any unterminated tokens. - * - * @return the List of chip values - */ - @NonNull - public List getChipValues() { - List chipValues = new ArrayList<>(); - - List chips = getAllChips(); - for (Chip chip : chips) { - chipValues.add(chip.getText().toString()); - } - - return chipValues; - } - - /** - * Returns a List of the string values of all the tokens (unchipped text) in the text - * (obtained through {@link ChipTokenizer#findAllTokens(CharSequence)}). This does not include any chipped text. - * - * @return the List of token values - */ - @NonNull - public List getTokenValues() { - List tokenValues = new ArrayList<>(); - - if (mChipTokenizer != null) { - Editable text = getText(); - List> unterminatedTokenIndexes = mChipTokenizer.findAllTokens(text); - for (Pair indexes : unterminatedTokenIndexes) { - String tokenValue = text.subSequence(indexes.first, indexes.second).toString(); - tokenValues.add(tokenValue); - } - } - - return tokenValues; - } - - /** - * Returns a combination of the chip values and token values in the text. - * - * @return the List of all chip and token values - * @see #getChipValues() - * @see #getTokenValues() - */ - @NonNull - public List getChipAndTokenValues() { - List chipAndTokenValues = new ArrayList<>(); - chipAndTokenValues.addAll(getChipValues()); - chipAndTokenValues.addAll(getTokenValues()); - return chipAndTokenValues; - } - - public boolean ignoreThreshold = false; - - @Override - public boolean enoughToFilter() { - return ignoreThreshold || super.enoughToFilter(); - } - - public OnDismissListener onDismissListener = null; - - @Override - public void dismissDropDown() { - if (onDismissListener != null) - onDismissListener.onDismiss(); - super.dismissDropDown(); - } - - @Override - public String toString() { - try { - return getTextWithPlainTextSpans(0, getText().length()).toString(); - } catch (ClassCastException ex) { // Exception is thrown by cast in getText() on some LG devices - return super.toString(); - } catch (StringIndexOutOfBoundsException e) { - throw new StringIndexOutOfBoundsException(String.format("%s \nError converting toString() [%s]", e.getMessage(), getText().toString())); - } - } - - private class ChipTokenizerWrapper implements Tokenizer { - - @NonNull - private ChipTokenizer mChipTokenizer; - - public ChipTokenizerWrapper(@NonNull ChipTokenizer chipTokenizer) { - mChipTokenizer = chipTokenizer; - } - - @Override - public int findTokenStart(CharSequence text, int cursor) { - return mChipTokenizer.findTokenStart(text, cursor); - } - - @Override - public int findTokenEnd(CharSequence text, int cursor) { - return mChipTokenizer.findTokenEnd(text, cursor); - } - - @Override - public CharSequence terminateToken(CharSequence text) { - return mChipTokenizer.terminateToken(text, null); - } - } - - public interface OnChipClickListener { - - /** - * Called when a chip in this TextView is touched. This callback is triggered by the {@link MotionEvent#ACTION_UP} event. - * - * @param chip the {@link Chip} that was touched - * @param event the {@link MotionEvent} that caused the touch - */ - void onChipClick(Chip chip, MotionEvent event); - } - - public interface OnChipRemoveListener { - - /** - * Called when a chip in this TextView is removed - * - * @param chip the {@link Chip} that was removed - */ - void onChipRemove(Chip chip); - } - - private class SingleTapListener extends GestureDetector.SimpleOnGestureListener { - - /** - * @param e the {@link MotionEvent} passed to the GestureDetector - * @return true if singleTapUp (click) was detected - */ - @Override - public boolean onSingleTapUp(MotionEvent e) { - return true; - } - } -} diff --git a/nachos/src/main/java/com/hootsuite/nachos/chip/Chip.java b/nachos/src/main/java/com/hootsuite/nachos/chip/Chip.java deleted file mode 100644 index a370eb26..00000000 --- a/nachos/src/main/java/com/hootsuite/nachos/chip/Chip.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.hootsuite.nachos.chip; - - -import androidx.annotation.Nullable; - -public interface Chip { - - /** - * @return the text represented by this Chip - */ - CharSequence getText(); - - /** - * @return the data associated with this Chip or null if no data is associated with it - */ - @Nullable - Object getData(); - - /** - * @return the width of the Chip or -1 if the Chip hasn't been given the chance to calculate its width - */ - int getWidth(); - - /** - * Sets the UI state. - * - * @param stateSet one of the state constants in {@link android.view.View} - */ - void setState(int[] stateSet); -} diff --git a/nachos/src/main/java/com/hootsuite/nachos/chip/ChipCreator.java b/nachos/src/main/java/com/hootsuite/nachos/chip/ChipCreator.java deleted file mode 100644 index c38f5cff..00000000 --- a/nachos/src/main/java/com/hootsuite/nachos/chip/ChipCreator.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.hootsuite.nachos.chip; - -import android.content.Context; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.hootsuite.nachos.ChipConfiguration; - -/** - * Interface to allow the creation and configuration of chips - * - * @param The type of {@link Chip} that the implementation will create/configure - */ -public interface ChipCreator { - - /** - * Creates a chip from the given context and text. Use this method when creating a brand new chip from a piece of text. - * - * @param context the {@link Context} to use to initialize the chip - * @param text the text the Chip should represent - * @param data the data to associate with the Chip, or null to associate no data - * @return the created chip - */ - C createChip(@NonNull Context context, @NonNull CharSequence text, @Nullable Object data); - - /** - * Creates a chip from the given context and existing chip. Use this method when recreating a chip from an existing one. - * - * @param context the {@link Context} to use to initialize the chip - * @param existingChip the chip that the created chip should be based on - * @return the created chip - */ - C createChip(@NonNull Context context, @NonNull C existingChip); - - /** - * Applies the given {@link ChipConfiguration} to the given {@link Chip}. Use this method to customize the appearance/behavior of a chip before - * adding it to the text. - * - * @param chip the chip to configure - * @param chipConfiguration the configuration to apply to the chip - */ - void configureChip(@NonNull C chip, @NonNull ChipConfiguration chipConfiguration); -} diff --git a/nachos/src/main/java/com/hootsuite/nachos/chip/ChipInfo.java b/nachos/src/main/java/com/hootsuite/nachos/chip/ChipInfo.java deleted file mode 100644 index 69b8ea4c..00000000 --- a/nachos/src/main/java/com/hootsuite/nachos/chip/ChipInfo.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.hootsuite.nachos.chip; - -public class ChipInfo { - - private final CharSequence mText; - private final Object mData; - - public ChipInfo(CharSequence text, Object data) { - this.mText = text; - this.mData = data; - } - - public CharSequence getText() { - return mText; - } - - public Object getData() { - return mData; - } -} diff --git a/nachos/src/main/java/com/hootsuite/nachos/chip/ChipSpan.java b/nachos/src/main/java/com/hootsuite/nachos/chip/ChipSpan.java deleted file mode 100644 index 652f5550..00000000 --- a/nachos/src/main/java/com/hootsuite/nachos/chip/ChipSpan.java +++ /dev/null @@ -1,511 +0,0 @@ -package com.hootsuite.nachos.chip; - -import android.content.Context; -import android.content.res.ColorStateList; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.RectF; -import android.graphics.drawable.Drawable; -import android.text.style.ImageSpan; - -import androidx.annotation.Dimension; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.content.ContextCompat; - -import com.hootsuite.nachos.R; - -/** - * A Span that displays text and an optional icon inside of a material design chip. The chip's dimensions, colors etc. can be extensively customized - * through the various setter methods available in this class. - * The basic structure of the chip is the following: - * For chips with the icon on right: - *

- *
- *                                  (chip vertical spacing / 2)
- *                  ----------------------------------------------------------
- *                |                                                            |
- * (left margin)  |  (padding edge)   text   (padding between image)   icon    |   (right margin)
- *                |                                                            |
- *                  ----------------------------------------------------------
- *                                  (chip vertical spacing / 2)
- *
- *      
- * For chips with the icon on the left (see {@link #setShowIconOnLeft(boolean)}): - *
- *
- *                                  (chip vertical spacing / 2)
- *                  ----------------------------------------------------------
- *                |                                                            |
- * (left margin)  |   icon  (padding between image)   text   (padding edge)    |   (right margin)
- *                |                                                            |
- *                  ----------------------------------------------------------
- *                                  (chip vertical spacing / 2)
- *     
- */ -public class ChipSpan extends ImageSpan implements Chip { - - private static final float SCALE_PERCENT_OF_CHIP_HEIGHT = 0.70f; - private static final boolean ICON_ON_LEFT_DEFAULT = true; - - private int[] mStateSet = new int[]{}; - - private String mEllipsis; - - private ColorStateList mDefaultBackgroundColor; - private ColorStateList mBackgroundColor; - private int mTextColor; - private int mCornerRadius = -1; - private int mIconBackgroundColor; - - private int mTextSize = -1; - private int mPaddingEdgePx; - private int mPaddingBetweenImagePx; - private int mLeftMarginPx; - private int mRightMarginPx; - private int mMaxAvailableWidth = -1; - - private CharSequence mText; - private String mTextToDraw; - - private Drawable mIcon; - private boolean mShowIconOnLeft = ICON_ON_LEFT_DEFAULT; - - private int mChipVerticalSpacing = 0; - private int mChipHeight = -1; - private int mChipWidth = -1; - private int mIconWidth; - - private int mCachedSize = -1; - - private Object mData; - - /** - * Constructs a new ChipSpan. - * - * @param context a {@link Context} that will be used to retrieve default configurations from resource files - * @param text the text for the ChipSpan to display - * @param icon an optional icon (can be {@code null}) for the ChipSpan to display - */ - public ChipSpan(@NonNull Context context, @NonNull CharSequence text, @Nullable Drawable icon, Object data) { - super(icon); - mIcon = icon; - mText = text; - mTextToDraw = mText.toString(); - - mEllipsis = context.getString(R.string.chip_ellipsis); - - mDefaultBackgroundColor = ContextCompat.getColorStateList(context, R.color.chip_material_background); - mBackgroundColor = mDefaultBackgroundColor; - - mTextColor = ContextCompat.getColor(context, R.color.chip_default_text_color); - mIconBackgroundColor = ContextCompat.getColor(context, R.color.chip_default_icon_background_color); - - Resources resources = context.getResources(); - mPaddingEdgePx = resources.getDimensionPixelSize(R.dimen.chip_default_padding_edge); - mPaddingBetweenImagePx = resources.getDimensionPixelSize(R.dimen.chip_default_padding_between_image); - mLeftMarginPx = resources.getDimensionPixelSize(R.dimen.chip_default_left_margin); - mRightMarginPx = resources.getDimensionPixelSize(R.dimen.chip_default_right_margin); - - mData = data; - } - - /** - * Copy constructor to recreate a ChipSpan from an existing one - * - * @param context a {@link Context} that will be used to retrieve default configurations from resource files - * @param chipSpan the ChipSpan to copy - */ - public ChipSpan(@NonNull Context context, @NonNull ChipSpan chipSpan) { - this(context, chipSpan.getText(), chipSpan.getDrawable(), chipSpan.getData()); - - mDefaultBackgroundColor = chipSpan.mDefaultBackgroundColor; - mTextColor = chipSpan.mTextColor; - mIconBackgroundColor = chipSpan.mIconBackgroundColor; - mCornerRadius = chipSpan.mCornerRadius; - - mTextSize = chipSpan.mTextSize; - mPaddingEdgePx = chipSpan.mPaddingEdgePx; - mPaddingBetweenImagePx = chipSpan.mPaddingBetweenImagePx; - mLeftMarginPx = chipSpan.mLeftMarginPx; - mRightMarginPx = chipSpan.mRightMarginPx; - mMaxAvailableWidth = chipSpan.mMaxAvailableWidth; - - mShowIconOnLeft = chipSpan.mShowIconOnLeft; - - mChipVerticalSpacing = chipSpan.mChipVerticalSpacing; - mChipHeight = chipSpan.mChipHeight; - - mStateSet = chipSpan.mStateSet; - } - - @Override - public Object getData() { - return mData; - } - - /** - * Sets the height of the chip. This height should not include any extra spacing (for extra vertical spacing call {@link #setChipVerticalSpacing(int)}). - * The background of the chip will fill the full height provided here. If this method is never called, the chip will have the height of one full line - * of text by default. If {@code -1} is passed here, the chip will revert to this default behavior. - * - * @param chipHeight the height to set in pixels - */ - public void setChipHeight(int chipHeight) { - mChipHeight = chipHeight; - } - - /** - * Sets the vertical spacing to include in between chips. Half of the value set here will be placed as empty space above the chip and half the value - * will be placed as empty space below the chip. Therefore chips on consecutive lines will have the full value as vertical space in between them. - * This spacing is achieved by adjusting the font metrics used by the text view containing these chips; however it does not come into effect until - * at least one chip is created. Note that vertical spacing is dependent on having a fixed chip height (set in {@link #setChipHeight(int)}). If a - * height is not specified in that method, the value set here will be ignored. - * - * @param chipVerticalSpacing the vertical spacing to set in pixels - */ - public void setChipVerticalSpacing(int chipVerticalSpacing) { - mChipVerticalSpacing = chipVerticalSpacing; - } - - /** - * Sets the font size for the chip's text. If this method is never called, the chip text will have the same font size as the text in the TextView - * containing this chip by default. If {@code -1} is passed here, the chip will revert to this default behavior. - * - * @param size the font size to set in pixels - */ - public void setTextSize(int size) { - mTextSize = size; - invalidateCachedSize(); - } - - /** - * Sets the color for the chip's text. - * - * @param color the color to set (as a hexadecimal number in the form 0xAARRGGBB) - */ - public void setTextColor(int color) { - mTextColor = color; - } - - /** - * Sets where the icon (if an icon was provided in the constructor) will appear. - * - * @param showIconOnLeft if true, the icon will appear on the left, otherwise the icon will appear on the right - */ - public void setShowIconOnLeft(boolean showIconOnLeft) { - this.mShowIconOnLeft = showIconOnLeft; - invalidateCachedSize(); - } - - /** - * Sets the left margin. This margin will appear as empty space (it will not share the chip's background color) to the left of the chip. - * - * @param leftMarginPx the left margin to set in pixels - */ - public void setLeftMargin(int leftMarginPx) { - mLeftMarginPx = leftMarginPx; - invalidateCachedSize(); - } - - /** - * Sets the right margin. This margin will appear as empty space (it will not share the chip's background color) to the right of the chip. - * - * @param rightMarginPx the right margin to set in pixels - */ - public void setRightMargin(int rightMarginPx) { - this.mRightMarginPx = rightMarginPx; - invalidateCachedSize(); - } - - /** - * Sets the background color. To configure which color in the {@link ColorStateList} is shown you can call {@link #setState(int[])}. - * Passing {@code null} here will cause the chip to revert to it's default background. - * - * @param backgroundColor a {@link ColorStateList} containing backgrounds for different states. - * @see #setState(int[]) - */ - public void setBackgroundColor(@Nullable ColorStateList backgroundColor) { - mBackgroundColor = backgroundColor != null ? backgroundColor : mDefaultBackgroundColor; - } - - /** - * Sets the chip background corner radius. - * - * @param cornerRadius The corner radius value, in pixels. - */ - public void setCornerRadius(@Dimension int cornerRadius) { - mCornerRadius = cornerRadius; - } - - /** - * Sets the icon background color. This is the color of the circle that gets drawn behind the icon passed to the - * {@link #ChipSpan(Context, CharSequence, Drawable, Object)} constructor} - * - * @param iconBackgroundColor the icon background color to set (as a hexadecimal number in the form 0xAARRGGBB) - */ - public void setIconBackgroundColor(int iconBackgroundColor) { - mIconBackgroundColor = iconBackgroundColor; - } - - public void setMaxAvailableWidth(int maxAvailableWidth) { - mMaxAvailableWidth = maxAvailableWidth; - invalidateCachedSize(); - } - - /** - * Sets the UI state. This state will be reflected in the background color drawn for the chip. - * - * @param stateSet one of the state constants in {@link android.view.View} - * @see #setBackgroundColor(ColorStateList) - */ - @Override - public void setState(int[] stateSet) { - this.mStateSet = stateSet != null ? stateSet : new int[]{}; - } - - @Override - public CharSequence getText() { - return mText; - } - - @Override - public int getWidth() { - // If we haven't actually calculated a chip width yet just return -1, otherwise return the chip width + margins - return mChipWidth != -1 ? (mLeftMarginPx + mChipWidth + mRightMarginPx) : -1; - } - - @Override - public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) { - boolean usingFontMetrics = (fm != null); - - // Adjust the font metrics regardless of whether or not there is a cached size so that the text view can maintain its height - if (usingFontMetrics) { - adjustFontMetrics(paint, fm); - } - - if (mCachedSize == -1 && usingFontMetrics) { - mIconWidth = (mIcon != null) ? calculateChipHeight(fm.top, fm.bottom) : 0; - - int actualWidth = calculateActualWidth(paint); - mCachedSize = actualWidth; - - if (mMaxAvailableWidth != -1) { - int maxAvailableWidthMinusMargins = mMaxAvailableWidth - mLeftMarginPx - mRightMarginPx; - if (actualWidth > maxAvailableWidthMinusMargins) { - mTextToDraw = mText + mEllipsis; - - while ((calculateActualWidth(paint) > maxAvailableWidthMinusMargins) && mTextToDraw.length() > 0) { - int lastCharacterIndex = mTextToDraw.length() - mEllipsis.length() - 1; - if (lastCharacterIndex < 0) { - break; - } - mTextToDraw = mTextToDraw.substring(0, lastCharacterIndex) + mEllipsis; - } - - // Avoid a negative width - mChipWidth = Math.max(0, maxAvailableWidthMinusMargins); - mCachedSize = mMaxAvailableWidth; - } - } - } - - return mCachedSize; - } - - private int calculateActualWidth(Paint paint) { - // Only change the text size if a text size was set - if (mTextSize != -1) { - paint.setTextSize(mTextSize); - } - - int totalPadding = mPaddingEdgePx; - - // Find text width - Rect bounds = new Rect(); - paint.getTextBounds(mTextToDraw, 0, mTextToDraw.length(), bounds); - int textWidth = bounds.width(); - - if (mIcon != null) { - totalPadding += mPaddingBetweenImagePx; - } else { - totalPadding += mPaddingEdgePx; - } - - mChipWidth = totalPadding + textWidth + mIconWidth; - return getWidth(); - } - - public void invalidateCachedSize() { - mCachedSize = -1; - } - - /** - * Adjusts the provided font metrics to make it seem like the font takes up {@code mChipHeight + mChipVerticalSpacing} pixels in height. - * This effectively ensures that the TextView will have a height equal to {@code mChipHeight + mChipVerticalSpacing} + whatever padding it has set. - * In {@link #draw(Canvas, CharSequence, int, int, float, int, int, int, Paint)} the chip itself is drawn to that it is vertically centered with - * {@code mChipVerticalSpacing / 2} pixels of space above and below it - * - * @param paint the paint whose font metrics should be adjusted - * @param fm the font metrics object to populate through {@link Paint#getFontMetricsInt(Paint.FontMetricsInt)} - */ - private void adjustFontMetrics(Paint paint, Paint.FontMetricsInt fm) { - // Only actually adjust font metrics if we have a chip height set - if (mChipHeight != -1) { - paint.getFontMetricsInt(fm); - int textHeight = fm.descent - fm.ascent; - // Break up the vertical spacing in half because half will go above the chip, half will go below the chip - int halfSpacing = mChipVerticalSpacing / 2; - - // Given that the text is centered vertically within the chip, the amount of space above or below the text (inbetween the text and chip) - // is half their difference in height: - int spaceBetweenChipAndText = (mChipHeight - textHeight) / 2; - - int textTop = fm.top; - int chipTop = fm.top - spaceBetweenChipAndText; - - int textBottom = fm.bottom; - int chipBottom = fm.bottom + spaceBetweenChipAndText; - - // The text may have been taller to begin with so we take the most negative coordinate (highest up) to be the top of the content - int topOfContent = Math.min(textTop, chipTop); - // Same as above but we want the largest positive coordinate (lowest down) to be the bottom of the content - int bottomOfContent = Math.max(textBottom, chipBottom); - - // Shift the top up by halfSpacing and the bottom down by halfSpacing - int topOfContentWithSpacing = topOfContent - halfSpacing; - int bottomOfContentWithSpacing = bottomOfContent + halfSpacing; - - // Change the font metrics so that the TextView thinks the font takes up the vertical space of a chip + spacing - fm.ascent = topOfContentWithSpacing; - fm.descent = bottomOfContentWithSpacing; - fm.top = topOfContentWithSpacing; - fm.bottom = bottomOfContentWithSpacing; - } - } - - private int calculateChipHeight(int top, int bottom) { - // If a chip height was set we can return that, otherwise calculate it from top and bottom - return mChipHeight != -1 ? mChipHeight : bottom - top; - } - - @Override - public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) { - // Shift everything mLeftMarginPx to the left to create an empty space on the left (creating the margin) - x += mLeftMarginPx; - if (mChipHeight != -1) { - // If we set a chip height, adjust to vertically center chip in the line - // Adding (bottom - top) / 2 shifts the chip down so the top of it will be centered vertically - // Subtracting (mChipHeight / 2) shifts the chip back up so that the center of it will be centered vertically (as desired) - top += ((bottom - top) / 2) - (mChipHeight / 2); - bottom = top + mChipHeight; - } - - // Perform actual drawing - drawBackground(canvas, x, top, bottom, paint); - drawText(canvas, x, top, bottom, paint, mTextToDraw); - if (mIcon != null) { - drawIcon(canvas, x, top, bottom, paint); - } - } - - private void drawBackground(Canvas canvas, float x, int top, int bottom, Paint paint) { - int backgroundColor = mBackgroundColor.getColorForState(mStateSet, mBackgroundColor.getDefaultColor()); - paint.setColor(backgroundColor); - int height = calculateChipHeight(top, bottom); - RectF rect = new RectF(x, top, x + mChipWidth, bottom); - int cornerRadius = (mCornerRadius != -1) ? mCornerRadius : height / 2; - canvas.drawRoundRect(rect, cornerRadius, cornerRadius, paint); - paint.setColor(mTextColor); - } - - private void drawText(Canvas canvas, float x, int top, int bottom, Paint paint, CharSequence text) { - if (mTextSize != -1) { - paint.setTextSize(mTextSize); - } - int height = calculateChipHeight(top, bottom); - Paint.FontMetrics fm = paint.getFontMetrics(); - - // The top value provided here is the y coordinate for the very top of the chip - // The y coordinate we are calculating is where the baseline of the text will be drawn - // Our objective is to have the midpoint between the top and baseline of the text be in line with the vertical center of the chip - // First we add height / 2 which will put the baseline at the vertical center of the chip - // Then we add half the height of the text which will lower baseline so that the midpoint is at the vertical center of the chip as desired - float adjustedY = top + ((height / 2) + ((-fm.top - fm.bottom) / 2)); - - // The x coordinate provided here is the left-most edge of the chip - // If there is no icon or the icon is on the right, then the text will start at the left-most edge, but indented with the edge padding, so we - // add mPaddingEdgePx - // If there is an icon and it's on the left, the text will start at the left-most edge, but indented by the combined width of the icon and - // the padding between the icon and text, so we add (mIconWidth + mPaddingBetweenImagePx) - float adjustedX = x + ((mIcon == null || !mShowIconOnLeft) ? mPaddingEdgePx : (mIconWidth + mPaddingBetweenImagePx)); - - canvas.drawText(text, 0, text.length(), adjustedX, adjustedY, paint); - } - - private void drawIcon(Canvas canvas, float x, int top, int bottom, Paint paint) { - drawIconBackground(canvas, x, top, bottom, paint); - drawIconBitmap(canvas, x, top, bottom, paint); - } - - private void drawIconBackground(Canvas canvas, float x, int top, int bottom, Paint paint) { - int height = calculateChipHeight(top, bottom); - - paint.setColor(mIconBackgroundColor); - - // Since it's a circle the diameter is equal to the height, so the radius == diameter / 2 == height / 2 - int radius = height / 2; - // The coordinates that get passed to drawCircle are for the center of the circle - // x is the left edge of the chip, (x + mChipWidth) is the right edge of the chip - // So the center of the circle is one radius distance from either the left or right edge (depending on which side the icon is being drawn on) - float circleX = mShowIconOnLeft ? (x + radius) : (x + mChipWidth - radius); - // The y coordinate is always just one radius distance from the top - canvas.drawCircle(circleX, top + radius, radius, paint); - - paint.setColor(mTextColor); - } - - private void drawIconBitmap(Canvas canvas, float x, int top, int bottom, Paint paint) { - int height = calculateChipHeight(top, bottom); - - // Create a scaled down version of the bitmap to fit within the circle (whose diameter == height) - Bitmap iconBitmap = Bitmap.createBitmap(mIcon.getIntrinsicWidth(), mIcon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); - Bitmap scaledIconBitMap = scaleDown(iconBitmap, (float) height * SCALE_PERCENT_OF_CHIP_HEIGHT, true); - iconBitmap.recycle(); - Canvas bitmapCanvas = new Canvas(scaledIconBitMap); - mIcon.setBounds(0, 0, bitmapCanvas.getWidth(), bitmapCanvas.getHeight()); - mIcon.draw(bitmapCanvas); - - // We are drawing a square icon inside of a circle - // The coordinates we pass to canvas.drawBitmap have to be for the top-left corner of the bitmap - // The bitmap should be inset by half of (circle width - bitmap width) - // Since it's a circle, the circle's width is equal to it's height which is equal to the chip height - float xInsetWithinCircle = (height - bitmapCanvas.getWidth()) / 2; - - // The icon x coordinate is going to be insetWithinCircle pixels away from the left edge of the circle - // If the icon is on the left, the left edge of the circle is just x - // If the icon is on the right, the left edge of the circle is x + mChipWidth - height - float iconX = mShowIconOnLeft ? (x + xInsetWithinCircle) : (x + mChipWidth - height + xInsetWithinCircle); - - // The y coordinate works the same way (only it's always from the top edge) - float yInsetWithinCircle = (height - bitmapCanvas.getHeight()) / 2; - float iconY = top + yInsetWithinCircle; - - canvas.drawBitmap(scaledIconBitMap, iconX, iconY, paint); - } - - private Bitmap scaleDown(Bitmap realImage, float maxImageSize, boolean filter) { - float ratio = Math.min(maxImageSize / realImage.getWidth(), maxImageSize / realImage.getHeight()); - int width = Math.round(ratio * realImage.getWidth()); - int height = Math.round(ratio * realImage.getHeight()); - return Bitmap.createScaledBitmap(realImage, width, height, filter); - } - - @Override - public String toString() { - return mText.toString(); - } -} diff --git a/nachos/src/main/java/com/hootsuite/nachos/chip/ChipSpanChipCreator.java b/nachos/src/main/java/com/hootsuite/nachos/chip/ChipSpanChipCreator.java deleted file mode 100644 index 8e0278f0..00000000 --- a/nachos/src/main/java/com/hootsuite/nachos/chip/ChipSpanChipCreator.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.hootsuite.nachos.chip; - -import android.content.Context; -import android.content.res.ColorStateList; -import android.graphics.Color; - -import androidx.annotation.NonNull; - -import com.hootsuite.nachos.ChipConfiguration; - -public class ChipSpanChipCreator implements ChipCreator { - - @Override - public ChipSpan createChip(@NonNull Context context, @NonNull CharSequence text, Object data) { - return new ChipSpan(context, text, null, data); - } - - @Override - public ChipSpan createChip(@NonNull Context context, @NonNull ChipSpan existingChip) { - return new ChipSpan(context, existingChip); - } - - @Override - public void configureChip(@NonNull ChipSpan chip, @NonNull ChipConfiguration chipConfiguration) { - int chipHorizontalSpacing = chipConfiguration.getChipHorizontalSpacing(); - ColorStateList chipBackground = chipConfiguration.getChipBackground(); - int chipCornerRadius = chipConfiguration.getChipCornerRadius(); - int chipTextColor = chipConfiguration.getChipTextColor(); - int chipTextSize = chipConfiguration.getChipTextSize(); - int chipHeight = chipConfiguration.getChipHeight(); - int chipVerticalSpacing = chipConfiguration.getChipVerticalSpacing(); - int maxAvailableWidth = chipConfiguration.getMaxAvailableWidth(); - - if (chipHorizontalSpacing != -1) { - chip.setLeftMargin(chipHorizontalSpacing / 2); - chip.setRightMargin(chipHorizontalSpacing / 2); - } - if (chipBackground != null) { - chip.setBackgroundColor(chipBackground); - } - if (chipCornerRadius != -1) { - chip.setCornerRadius(chipCornerRadius); - } - if (chipTextColor != Color.TRANSPARENT) { - chip.setTextColor(chipTextColor); - } - if (chipTextSize != -1) { - chip.setTextSize(chipTextSize); - } - if (chipHeight != -1) { - chip.setChipHeight(chipHeight); - } - if (chipVerticalSpacing != -1) { - chip.setChipVerticalSpacing(chipVerticalSpacing); - } - if (maxAvailableWidth != -1) { - chip.setMaxAvailableWidth(maxAvailableWidth); - } - } -} diff --git a/nachos/src/main/java/com/hootsuite/nachos/terminator/ChipTerminatorHandler.java b/nachos/src/main/java/com/hootsuite/nachos/terminator/ChipTerminatorHandler.java deleted file mode 100644 index f97d430e..00000000 --- a/nachos/src/main/java/com/hootsuite/nachos/terminator/ChipTerminatorHandler.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.hootsuite.nachos.terminator; - -import android.text.Editable; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.hootsuite.nachos.tokenizer.ChipTokenizer; - -import java.util.Map; - -/** - * This interface is used to handle the management of characters that should trigger the creation of chips in a text view. - * - * @see ChipTokenizer - */ -public interface ChipTerminatorHandler { - - /** - * When a chip terminator character is encountered in newly inserted text, all tokens in the whole text view will be chipified - */ - int BEHAVIOR_CHIPIFY_ALL = 0; - - /** - * When a chip terminator character is encountered in newly inserted text, only the current token (that in which the chip terminator character - * was found) will be chipified. This token may extend beyond where the chip terminator character was located. - */ - int BEHAVIOR_CHIPIFY_CURRENT_TOKEN = 1; - - /** - * When a chip terminator character is encountered in newly inserted text, only the text from the previous chip up until the chip terminator - * character will be chipified. This may not be an entire token. - */ - int BEHAVIOR_CHIPIFY_TO_TERMINATOR = 2; - - /** - * Constant for use with {@link #setPasteBehavior(int)}. Use this if a paste should behave the same as a standard text input (the chip temrinators - * will all behave according to their pre-determined behavior set through {@link #addChipTerminator(char, int)} or {@link #setChipTerminators(Map)}). - */ - int PASTE_BEHAVIOR_USE_DEFAULT = -1; - - /** - * Sets all the characters that will be marked as chip terminators. This will replace any previously set chip terminators. - * - * @param chipTerminators a map of characters to be marked as chip terminators to behaviors that describe how to respond to the characters, or null - * to remove all chip terminators - */ - void setChipTerminators(@Nullable Map chipTerminators); - - /** - * Adds a character as a chip terminator. When the provided character is encountered in entered text, the nearby text will be chipified according - * to the behavior provided here. - * {@code behavior} Must be one of: - *
    - *
  • {@link #BEHAVIOR_CHIPIFY_ALL}
  • - *
  • {@link #BEHAVIOR_CHIPIFY_CURRENT_TOKEN}
  • - *
  • {@link #BEHAVIOR_CHIPIFY_TO_TERMINATOR}
  • - *
- * - * @param character the character to mark as a chip terminator - * @param behavior the behavior describing how to respond to the chip terminator - */ - void addChipTerminator(char character, int behavior); - - /** - * Customizes the way paste events are handled. - * If one of: - *
    - *
  • {@link #BEHAVIOR_CHIPIFY_ALL}
  • - *
  • {@link #BEHAVIOR_CHIPIFY_CURRENT_TOKEN}
  • - *
  • {@link #BEHAVIOR_CHIPIFY_TO_TERMINATOR}
  • - *
- * is passed, all chip terminators will be handled with that behavior when a paste event occurs. - * If {@link #PASTE_BEHAVIOR_USE_DEFAULT} is passed, whatever behavior is configured for a particular chip terminator - * (through {@link #setChipTerminators(Map)} or {@link #addChipTerminator(char, int)} will be used for that chip terminator - * - * @param pasteBehavior the behavior to use on a paste event - */ - void setPasteBehavior(int pasteBehavior); - - /** - * Parses the provided text looking for characters marked as chip terminators through {@link #addChipTerminator(char, int)} and {@link #setChipTerminators(Map)}. - * The provided {@link Editable} will be modified if chip terminators are encountered. - * - * @param tokenizer the {@link ChipTokenizer} to use to identify and chipify tokens in the text - * @param text the text in which to search for chip terminators tokens to be chipped - * @param start the index at which to begin looking for chip terminators (inclusive) - * @param end the index at which to end looking for chip terminators (exclusive) - * @param isPasteEvent true if this handling is for a paste event in which case the behavior set in {@link #setPasteBehavior(int)} will be used, - * otherwise false - * @return an non-negative integer indicating the index where the cursor (selection) should be placed once the handling is complete, - * or a negative integer indicating that the cursor should not be moved. - */ - int findAndHandleChipTerminators(@NonNull ChipTokenizer tokenizer, @NonNull Editable text, int start, int end, boolean isPasteEvent); -} diff --git a/nachos/src/main/java/com/hootsuite/nachos/terminator/DefaultChipTerminatorHandler.java b/nachos/src/main/java/com/hootsuite/nachos/terminator/DefaultChipTerminatorHandler.java deleted file mode 100644 index 75cb9b0d..00000000 --- a/nachos/src/main/java/com/hootsuite/nachos/terminator/DefaultChipTerminatorHandler.java +++ /dev/null @@ -1,115 +0,0 @@ -package com.hootsuite.nachos.terminator; - -import android.text.Editable; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.hootsuite.nachos.tokenizer.ChipTokenizer; - -import java.util.HashMap; -import java.util.Map; - -public class DefaultChipTerminatorHandler implements ChipTerminatorHandler { - - @Nullable - private Map mChipTerminators; - private int mPasteBehavior = BEHAVIOR_CHIPIFY_TO_TERMINATOR; - - @Override - public void setChipTerminators(@Nullable Map chipTerminators) { - mChipTerminators = chipTerminators; - } - - @Override - public void addChipTerminator(char character, int behavior) { - if (mChipTerminators == null) { - mChipTerminators = new HashMap<>(); - } - - mChipTerminators.put(character, behavior); - } - - @Override - public void setPasteBehavior(int pasteBehavior) { - mPasteBehavior = pasteBehavior; - } - - @Override - public int findAndHandleChipTerminators(@NonNull ChipTokenizer tokenizer, @NonNull Editable text, int start, int end, boolean isPasteEvent) { - // If we don't have a tokenizer or any chip terminators, there's nothing to look for - if (mChipTerminators == null) { - return -1; - } - - TextIterator textIterator = new TextIterator(text, start, end); - int selectionIndex = -1; - - characterLoop: - while (textIterator.hasNextCharacter()) { - char theChar = textIterator.nextCharacter(); - if (isChipTerminator(theChar)) { - int behavior = (isPasteEvent && mPasteBehavior != PASTE_BEHAVIOR_USE_DEFAULT) ? mPasteBehavior : mChipTerminators.get(theChar); - int newSelection = -1; - switch (behavior) { - case BEHAVIOR_CHIPIFY_ALL: - selectionIndex = handleChipifyAll(textIterator, tokenizer); - break characterLoop; - case BEHAVIOR_CHIPIFY_CURRENT_TOKEN: - newSelection = handleChipifyCurrentToken(textIterator, tokenizer); - break; - case BEHAVIOR_CHIPIFY_TO_TERMINATOR: - newSelection = handleChipifyToTerminator(textIterator, tokenizer); - break; - } - - if (newSelection != -1) { - selectionIndex = newSelection; - } - } - } - - return selectionIndex; - } - - private int handleChipifyAll(TextIterator textIterator, ChipTokenizer tokenizer) { - textIterator.deleteCharacter(true); - tokenizer.terminateAllTokens(textIterator.getText()); - return textIterator.totalLength(); - } - - private int handleChipifyCurrentToken(TextIterator textIterator, ChipTokenizer tokenizer) { - textIterator.deleteCharacter(true); - Editable text = textIterator.getText(); - int index = textIterator.getIndex(); - int tokenStart = tokenizer.findTokenStart(text, index); - int tokenEnd = tokenizer.findTokenEnd(text, index); - if (tokenStart < tokenEnd) { - CharSequence chippedText = tokenizer.terminateToken(text.subSequence(tokenStart, tokenEnd), null); - textIterator.replace(tokenStart, tokenEnd, chippedText); - return tokenStart + chippedText.length(); - } - return -1; - } - - private int handleChipifyToTerminator(TextIterator textIterator, ChipTokenizer tokenizer) { - Editable text = textIterator.getText(); - int index = textIterator.getIndex(); - if (index > 0) { - int tokenStart = tokenizer.findTokenStart(text, index); - if (tokenStart < index) { - CharSequence chippedText = tokenizer.terminateToken(text.subSequence(tokenStart, index), null); - textIterator.replace(tokenStart, index + 1, chippedText); - } else { - textIterator.deleteCharacter(false); - } - } else { - textIterator.deleteCharacter(false); - } - return -1; - } - - private boolean isChipTerminator(char character) { - return mChipTerminators != null && mChipTerminators.keySet().contains(character); - } -} diff --git a/nachos/src/main/java/com/hootsuite/nachos/terminator/TextIterator.java b/nachos/src/main/java/com/hootsuite/nachos/terminator/TextIterator.java deleted file mode 100644 index 7c25d4c9..00000000 --- a/nachos/src/main/java/com/hootsuite/nachos/terminator/TextIterator.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.hootsuite.nachos.terminator; - -import android.text.Editable; - -public class TextIterator { - - private Editable mText; - private int mStart; - private int mEnd; - - private int mIndex; - - public TextIterator(Editable text, int start, int end) { - mText = text; - mStart = start; - mEnd = end; - - mIndex = mStart - 1; // Subtract 1 so that the first call to nextCharacter() will return the first character - } - - public int totalLength() { - return mText.length(); - } - - public int windowLength() { - return mEnd - mStart; - } - - public Editable getText() { - return mText; - } - - public int getIndex() { - return mIndex; - } - - public boolean hasNextCharacter() { - return (mIndex + 1) < mEnd; - } - - public char nextCharacter() { - mIndex++; - return mText.charAt(mIndex); - } - - public void deleteCharacter(boolean maintainIndex) { - mText.replace(mIndex, mIndex + 1, ""); - if (!maintainIndex) { - mIndex--; - } - mEnd--; - } - - public void replace(int replaceStart, int replaceEnd, CharSequence chippedText) { - mText.replace(replaceStart, replaceEnd, chippedText); - - // Update indexes - int newLength = chippedText.length(); - int oldLength = replaceEnd - replaceStart; - mIndex = replaceStart + newLength - 1; - mEnd += newLength - oldLength; - } -} diff --git a/nachos/src/main/java/com/hootsuite/nachos/tokenizer/BaseChipTokenizer.java b/nachos/src/main/java/com/hootsuite/nachos/tokenizer/BaseChipTokenizer.java deleted file mode 100644 index ba946b5b..00000000 --- a/nachos/src/main/java/com/hootsuite/nachos/tokenizer/BaseChipTokenizer.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.hootsuite.nachos.tokenizer; - -import android.text.Editable; -import android.text.Spanned; -import android.util.Pair; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.hootsuite.nachos.ChipConfiguration; -import com.hootsuite.nachos.chip.Chip; - -import java.util.ArrayList; -import java.util.List; - -/** - * Base implementation of the {@link ChipTokenizer} interface that performs no actions and returns default values. - * This class allows for the easy creation of a ChipTokenizer that only implements some of the methods of the interface. - */ -public abstract class BaseChipTokenizer implements ChipTokenizer { - - @Override - public void applyConfiguration(Editable text, ChipConfiguration chipConfiguration) { - // Do nothing - } - - @Override - public int findTokenStart(CharSequence charSequence, int i) { - // Do nothing - return 0; - } - - @Override - public int findTokenEnd(CharSequence charSequence, int i) { - // Do nothing - return 0; - } - - @NonNull - @Override - public List> findAllTokens(CharSequence text) { - // Do nothing - return new ArrayList<>(); - } - - @Override - public CharSequence terminateToken(CharSequence charSequence, @Nullable Object data) { - // Do nothing - return charSequence; - } - - @Override - public void terminateAllTokens(Editable text) { - // Do nothing - } - - @Override - public int findChipStart(Chip chip, Spanned text) { - // Do nothing - return 0; - } - - @Override - public int findChipEnd(Chip chip, Spanned text) { - // Do nothing - return 0; - } - - @NonNull - @Override - public Chip[] findAllChips(int start, int end, Spanned text) { - return new Chip[]{}; - } - - @Override - public void revertChipToToken(Chip chip, Editable text) { - // Do nothing - } - - @Override - public void deleteChip(Chip chip, Editable text) { - // Do nothing - } - - @Override - public void deleteChipAndPadding(Chip chip, Editable text) { - // Do nothing - } -} diff --git a/nachos/src/main/java/com/hootsuite/nachos/tokenizer/ChipTokenizer.java b/nachos/src/main/java/com/hootsuite/nachos/tokenizer/ChipTokenizer.java deleted file mode 100644 index 32d8f061..00000000 --- a/nachos/src/main/java/com/hootsuite/nachos/tokenizer/ChipTokenizer.java +++ /dev/null @@ -1,134 +0,0 @@ -package com.hootsuite.nachos.tokenizer; - -import android.text.Editable; -import android.text.Spanned; -import android.util.Pair; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.hootsuite.nachos.ChipConfiguration; -import com.hootsuite.nachos.chip.Chip; - -import java.util.List; - -/** - * An extension of {@link android.widget.MultiAutoCompleteTextView.Tokenizer Tokenizer} that provides extra support - * for chipification. - *

- * In the context of this interface, a token is considered to be plain (non-chipped) text. Once a token is terminated it becomes or contains a chip. - *

- *

- * The CharSequences passed to the ChipTokenizer methods may contain both chipped text - * and plain text so the tokenizer must have some method of distinguishing between the two (e.g. using a delimeter character. - * The {@link #terminateToken(CharSequence, Object)} method is where a chip can be formed and returned to replace the plain text. - * Whatever class the implementation deems to represent a chip, must implement the {@link Chip} interface. - *

- * - * @see SpanChipTokenizer - */ -public interface ChipTokenizer { - - /** - * Configures this ChipTokenizer to produce chips with the provided attributes. For each of these attributes, {@code -1} or {@code null} may be - * passed to indicate that the attribute may be ignored. - *

- * This will also apply the provided {@link ChipConfiguration} to any existing chips in the provided text. - *

- * - * @param text the text in which to search for existing chips to apply the configuration to - * @param chipConfiguration a {@link ChipConfiguration} containing customizations for the chips produced by this class - */ - void applyConfiguration(Editable text, ChipConfiguration chipConfiguration); - - /** - * Returns the start of the token that ends at offset - * cursor within text. - */ - int findTokenStart(CharSequence text, int cursor); - - /** - * Returns the end of the token (minus trailing punctuation) - * that begins at offset cursor within text. - */ - int findTokenEnd(CharSequence text, int cursor); - - /** - * Searches through {@code text} for any tokens. - * - * @param text the text in which to search for un-terminated tokens - * @return a list of {@link Pair}s of the form (startIndex, endIndex) containing the locations of all - * unterminated tokens - */ - @NonNull - List> findAllTokens(CharSequence text); - - /** - * Returns text, modified, if necessary, to ensure that - * it ends with a token terminator (for example a space or comma). - */ - CharSequence terminateToken(CharSequence text, @Nullable Object data); - - /** - * Terminates (converts from token into chip) all unterminated tokens in the provided text. - * This method CAN alter the provided text. - * - * @param text the text in which to terminate all tokens - */ - void terminateAllTokens(Editable text); - - /** - * Finds the index of the first character in {@code text} that is a part of {@code chip} - * - * @param chip the chip whose start should be found - * @param text the text in which to search for the start of {@code chip} - * @return the start index of the chip - */ - int findChipStart(Chip chip, Spanned text); - - /** - * Finds the index of the character after the last character in {@code text} that is a part of {@code chip} - * - * @param chip the chip whose end should be found - * @param text the text in which to search for the end of {@code chip} - * @return the end index of the chip - */ - int findChipEnd(Chip chip, Spanned text); - - /** - * Searches through {@code text} for any chips - * - * @param start index to start looking for terminated tokens (inclusive) - * @param end index to end looking for terminated tokens (exclusive) - * @param text the text in which to search for terminated tokens - * @return a list of objects implementing the {@link Chip} interface to represent the terminated tokens - */ - @NonNull - Chip[] findAllChips(int start, int end, Spanned text); - - /** - * Effectively does the opposite of {@link #terminateToken(CharSequence, Object)} by reverting the provided chip back into a token. - * This method CAN alter the provided text. - * - * @param chip the chip to revert into a token - * @param text the text in which the chip resides - */ - void revertChipToToken(Chip chip, Editable text); - - /** - * Removes a chip and any text it encompasses from {@code text}. This method CAN alter the provided text. - * - * @param chip the chip to remove - * @param text the text to remove the chip from - */ - void deleteChip(Chip chip, Editable text); - - /** - * Removes a chip, any text it encompasses AND any padding text (such as spaces) that may have been inserted when the chip was created in - * {@link #terminateToken(CharSequence, Object)} or after. This method CAN alter the provided text. - * - * @param chip the chip to remove - * @param text the text to remove the chip and padding from - */ - void deleteChipAndPadding(Chip chip, Editable text); -} diff --git a/nachos/src/main/java/com/hootsuite/nachos/tokenizer/SpanChipTokenizer.java b/nachos/src/main/java/com/hootsuite/nachos/tokenizer/SpanChipTokenizer.java deleted file mode 100644 index 79410e20..00000000 --- a/nachos/src/main/java/com/hootsuite/nachos/tokenizer/SpanChipTokenizer.java +++ /dev/null @@ -1,248 +0,0 @@ -package com.hootsuite.nachos.tokenizer; - -import android.content.Context; -import android.text.Editable; -import android.text.SpannableString; -import android.text.Spanned; -import android.util.Pair; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.hootsuite.nachos.ChipConfiguration; -import com.hootsuite.nachos.chip.Chip; -import com.hootsuite.nachos.chip.ChipCreator; -import com.hootsuite.nachos.chip.ChipSpan; - -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -/** - * A default implementation of {@link ChipTokenizer}. - * This implementation does the following: - *
    - *
  • Surrounds each token with a space and the Unit Separator ASCII control character (31) - See the diagram below - *
      - *
    • The spaces are included so that android keyboards can distinguish the chips as different words and provide accurate - * autocorrect suggestions
    • - *
    - *
  • - *
  • Replaces each token with a {@link ChipSpan} containing the same text, once the token terminates
  • - *
  • Uses the values passed to {@link #applyConfiguration(Editable, ChipConfiguration)} to configure any ChipSpans that get created
  • - *
- * Each terminated token will therefore look like the following (this is what will be returned from {@link #terminateToken(CharSequence, Object)}): - *
- *  -----------------------------------------------------------
- *  | SpannableString                                         |
- *  |   ----------------------------------------------------  |
- *  |   | ChipSpan                                         |  |
- *  |   |                                                  |  |
- *  |   |  space   separator    text    separator   space  |  |
- *  |   |                                                  |  |
- *  |   ----------------------------------------------------  |
- *  -----------------------------------------------------------
- * 
- * - * @see ChipSpan - */ -public class SpanChipTokenizer implements ChipTokenizer { - - /** - * The character used to separate chips internally is the US (Unit Separator) ASCII control character. - * This character is used because it's untypable so we have complete control over when chips are created. - */ - public static final char CHIP_SPAN_SEPARATOR = 31; - public static final char AUTOCORRECT_SEPARATOR = ' '; - - private Context mContext; - - @Nullable - private ChipConfiguration mChipConfiguration; - @NonNull - private ChipCreator mChipCreator; - @NonNull - private Class mChipClass; - - private Comparator> mReverseTokenIndexesSorter = new Comparator>() { - @Override - public int compare(Pair lhs, Pair rhs) { - return rhs.first - lhs.first; - } - }; - - public SpanChipTokenizer(Context context, @NonNull ChipCreator chipCreator, @NonNull Class chipClass) { - mContext = context; - mChipCreator = chipCreator; - mChipClass = chipClass; - } - - @Override - public void applyConfiguration(Editable text, ChipConfiguration chipConfiguration) { - mChipConfiguration = chipConfiguration; - - for (C chip : findAllChips(0, text.length(), text)) { - // Recreate the chips with the new configuration - int chipStart = findChipStart(chip, text); - deleteChip(chip, text); - text.insert(chipStart, terminateToken(mChipCreator.createChip(mContext, chip))); - } - } - - @Override - public int findTokenStart(CharSequence text, int cursor) { - int i = cursor; - - // Work backwards until we find a CHIP_SPAN_SEPARATOR - while (i > 0 && text.charAt(i - 1) != CHIP_SPAN_SEPARATOR) { - i--; - } - // Work forwards to skip over any extra whitespace at the beginning of the token - while (i > 0 && i < text.length() && Character.isWhitespace(text.charAt(i))) { - i++; - } - return i; - } - - @Override - public int findTokenEnd(CharSequence text, int cursor) { - int i = cursor; - int len = text.length(); - - // Work forwards till we find a CHIP_SPAN_SEPARATOR - while (i < len) { - if (text.charAt(i) == CHIP_SPAN_SEPARATOR) { - return (i - 1); // subtract one because the CHIP_SPAN_SEPARATOR will be preceded by a space - } else { - i++; - } - } - return len; - } - - @NonNull - @Override - public List> findAllTokens(CharSequence text) { - List> unterminatedTokens = new ArrayList<>(); - - boolean insideChip = false; - // Iterate backwards through the text (to avoid messing up indexes) - for (int index = text.length() - 1; index >= 0; index--) { - char theCharacter = text.charAt(index); - - // Every time we hit a CHIP_SPAN_SEPARATOR character we switch from being inside to outside - // or outside to inside a chip - // This check must happen before the whitespace check because CHIP_SPAN_SEPARATOR is considered a whitespace character - if (theCharacter == CHIP_SPAN_SEPARATOR) { - insideChip = !insideChip; - continue; - } - - // Completely skip over whitespace - if (Character.isWhitespace(theCharacter)) { - continue; - } - - // If we're ever outside a chip, see if the text we're in is a viable token for chipification - if (!insideChip) { - int tokenStart = findTokenStart(text, index); - int tokenEnd = findTokenEnd(text, index); - - // Can only actually be chipified if there's at least one character between them - if (tokenEnd - tokenStart >= 1) { - unterminatedTokens.add(new Pair<>(tokenStart, tokenEnd)); - index = tokenStart; - } - } - } - return unterminatedTokens; - } - - @Override - public CharSequence terminateToken(CharSequence text, @Nullable Object data) { - // Remove leading/trailing whitespace - CharSequence trimmedText = text.toString().trim(); - return terminateToken(mChipCreator.createChip(mContext, trimmedText, data)); - } - - private CharSequence terminateToken(C chip) { - if (chip == null) - return new SpannableString(""); - // Surround the text with CHIP_SPAN_SEPARATOR and spaces - // The spaces allow autocorrect to correctly identify words - String chipSeparator = Character.toString(CHIP_SPAN_SEPARATOR); - String autoCorrectSeparator = Character.toString(AUTOCORRECT_SEPARATOR); - CharSequence textWithSeparator = autoCorrectSeparator + chipSeparator + chip.getText() + chipSeparator + autoCorrectSeparator; - - // Build the container object to house the ChipSpan and space - SpannableString spannableString = new SpannableString(textWithSeparator); - - // Attach the ChipSpan - if (mChipConfiguration != null) { - mChipCreator.configureChip(chip, mChipConfiguration); - } - spannableString.setSpan(chip, 0, textWithSeparator.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - - return spannableString; - } - - @Override - public void terminateAllTokens(Editable text) { - List> unterminatedTokens = findAllTokens(text); - // Sort in reverse order (so index changes don't affect anything) - Collections.sort(unterminatedTokens, mReverseTokenIndexesSorter); - for (Pair indexes : unterminatedTokens) { - int start = indexes.first; - int end = indexes.second; - CharSequence textToChip = text.subSequence(start, end); - CharSequence chippedText = terminateToken(textToChip, null); - text.replace(start, end, chippedText); - } - } - - @Override - public int findChipStart(Chip chip, Spanned text) { - return text.getSpanStart(chip); - } - - @Override - public int findChipEnd(Chip chip, Spanned text) { - return text.getSpanEnd(chip); - } - - @SuppressWarnings("unchecked") - @NonNull - @Override - public C[] findAllChips(int start, int end, Spanned text) { - C[] spansArray = text.getSpans(start, end, mChipClass); - return (spansArray != null) ? spansArray : (C[]) Array.newInstance(mChipClass, 0); - } - - @Override - public void revertChipToToken(Chip chip, Editable text) { - int chipStart = findChipStart(chip, text); - int chipEnd = findChipEnd(chip, text); - text.removeSpan(chip); - text.replace(chipStart, chipEnd, chip.getText()); - } - - @Override - public void deleteChip(Chip chip, Editable text) { - int chipStart = findChipStart(chip, text); - int chipEnd = findChipEnd(chip, text); - text.removeSpan(chip); - // On the emulator for some reason the text automatically gets deleted and chipStart and chipEnd end up both being -1, so in that case we - // don't need to call text.delete(...) - if (chipStart != chipEnd) { - text.delete(chipStart, chipEnd); - } - } - - @Override - public void deleteChipAndPadding(Chip chip, Editable text) { - // This implementation does not add any extra padding outside of the span so we can just delete the chip normally - deleteChip(chip, text); - } -} diff --git a/nachos/src/main/java/com/hootsuite/nachos/validator/ChipifyingNachoValidator.java b/nachos/src/main/java/com/hootsuite/nachos/validator/ChipifyingNachoValidator.java deleted file mode 100644 index fa1aa571..00000000 --- a/nachos/src/main/java/com/hootsuite/nachos/validator/ChipifyingNachoValidator.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.hootsuite.nachos.validator; - -import android.text.SpannableStringBuilder; -import android.util.Pair; - -import androidx.annotation.NonNull; - -import com.hootsuite.nachos.tokenizer.ChipTokenizer; - -import java.util.List; - -/** - * A {@link NachoValidator} that deems text to be invalid if it contains - * unterminated tokens and fixes the text by chipifying all the unterminated tokens. - */ -public class ChipifyingNachoValidator implements NachoValidator { - - @Override - public boolean isValid(@NonNull ChipTokenizer chipTokenizer, CharSequence text) { - - // The text is considered valid if there are no unterminated tokens (everything is a chip) - List> unterminatedTokens = chipTokenizer.findAllTokens(text); - return unterminatedTokens.isEmpty(); - } - - @Override - public CharSequence fixText(@NonNull ChipTokenizer chipTokenizer, CharSequence invalidText) { - SpannableStringBuilder newText = new SpannableStringBuilder(invalidText); - chipTokenizer.terminateAllTokens(newText); - return newText; - } -} diff --git a/nachos/src/main/java/com/hootsuite/nachos/validator/IllegalCharacterIdentifier.java b/nachos/src/main/java/com/hootsuite/nachos/validator/IllegalCharacterIdentifier.java deleted file mode 100644 index 76f3f858..00000000 --- a/nachos/src/main/java/com/hootsuite/nachos/validator/IllegalCharacterIdentifier.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.hootsuite.nachos.validator; - -public interface IllegalCharacterIdentifier { - boolean isCharacterIllegal(Character c); -} diff --git a/nachos/src/main/java/com/hootsuite/nachos/validator/NachoValidator.java b/nachos/src/main/java/com/hootsuite/nachos/validator/NachoValidator.java deleted file mode 100644 index 6c798e7c..00000000 --- a/nachos/src/main/java/com/hootsuite/nachos/validator/NachoValidator.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.hootsuite.nachos.validator; - - -import androidx.annotation.NonNull; - -import com.hootsuite.nachos.tokenizer.ChipTokenizer; - -/** - * Interface used to ensure that a given CharSequence complies to a particular format. - */ -public interface NachoValidator { - - /** - * Validates the specified text. - * - * @return true If the text currently in the text editor is valid. - * @see #fixText(ChipTokenizer, CharSequence) - */ - boolean isValid(@NonNull ChipTokenizer chipTokenizer, CharSequence text); - - /** - * Corrects the specified text to make it valid. - * - * @param invalidText A string that doesn't pass validation: isValid(invalidText) - * returns false - * @return A string based on invalidText such as invoking isValid() on it returns true. - * @see #isValid(ChipTokenizer, CharSequence) - */ - CharSequence fixText(@NonNull ChipTokenizer chipTokenizer, CharSequence invalidText); -} diff --git a/nachos/src/main/project.properties b/nachos/src/main/project.properties deleted file mode 100644 index 70c5769d..00000000 --- a/nachos/src/main/project.properties +++ /dev/null @@ -1,2 +0,0 @@ -# See https://github.com/robolectric/robolectric/issues/1334 -android.library.reference.1=../../build/intermediates/exploded-aar/com.android.support/appcompat-v7/22.2.1' \ No newline at end of file diff --git a/nachos/src/main/res/color/chip_material_background.xml b/nachos/src/main/res/color/chip_material_background.xml deleted file mode 100644 index ec381b24..00000000 --- a/nachos/src/main/res/color/chip_material_background.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/nachos/src/main/res/values/attrs.xml b/nachos/src/main/res/values/attrs.xml deleted file mode 100644 index dcd632af..00000000 --- a/nachos/src/main/res/values/attrs.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/nachos/src/main/res/values/colors.xml b/nachos/src/main/res/values/colors.xml deleted file mode 100644 index a718d37d..00000000 --- a/nachos/src/main/res/values/colors.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - #DE000000 - #517FA4 - \ No newline at end of file diff --git a/nachos/src/main/res/values/dimens.xml b/nachos/src/main/res/values/dimens.xml deleted file mode 100644 index 8df9e5ad..00000000 --- a/nachos/src/main/res/values/dimens.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - 12dp - 8dp - 0dp - 0dp - \ No newline at end of file diff --git a/nachos/src/main/res/values/strings.xml b/nachos/src/main/res/values/strings.xml deleted file mode 100644 index 6c2b508b..00000000 --- a/nachos/src/main/res/values/strings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/nachos/src/main/res/values/styles.xml b/nachos/src/main/res/values/styles.xml deleted file mode 100644 index 5ef64347..00000000 --- a/nachos/src/main/res/values/styles.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 955021f9..f2de53d8 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,7 +3,7 @@ include ':wear' include ':codegen' include ':annotation' rootProject.name='Szkolny.eu' -include ':app', ':agendacalendarview', ':mhttp', ':szkolny-font', ':nachos' +include ':app', ':agendacalendarview', ':mhttp', ':szkolny-font' /* include ':Navigation' project(':Navigation').projectDir = new File(settingsDir, '../Navigation/navlib')*/ From 0615593d94de82fe09aad242b73696676b8a5185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 20 Mar 2021 21:34:14 +0100 Subject: [PATCH 007/113] [Gradle] Extract mhttp dependency. --- app/build.gradle | 2 +- mhttp/build.gradle | 51 -- mhttp/gradle.properties | 31 -- mhttp/src/main/AndroidManifest.xml | 4 - .../im/wangchao/mhttp/AbsCallbackHandler.java | 256 --------- .../main/java/im/wangchao/mhttp/Accept.java | 33 -- .../java/im/wangchao/mhttp/Android5SSL.java | 149 ------ .../main/java/im/wangchao/mhttp/BindApi.java | 28 - .../main/java/im/wangchao/mhttp/Callback.java | 40 -- .../java/im/wangchao/mhttp/Converter.java | 12 - .../main/java/im/wangchao/mhttp/HTTPS.java | 179 ------- .../main/java/im/wangchao/mhttp/MHttp.java | 252 --------- .../main/java/im/wangchao/mhttp/Method.java | 25 - .../main/java/im/wangchao/mhttp/Request.java | 503 ------------------ .../java/im/wangchao/mhttp/RequestParams.java | 378 ------------- .../main/java/im/wangchao/mhttp/Response.java | 63 --- .../java/im/wangchao/mhttp/ThreadMode.java | 43 -- .../im/wangchao/mhttp/URLInterceptor.java | 20 - .../java/im/wangchao/mhttp/body/FileBody.java | 53 -- .../java/im/wangchao/mhttp/body/JSONBody.java | 50 -- .../wangchao/mhttp/body/MediaTypeUtils.java | 53 -- .../wangchao/mhttp/body/OctetStreamBody.java | 88 --- .../mhttp/body/ProgressRequestBody.java | 70 --- .../mhttp/callback/BinaryCallbackHandler.java | 30 -- .../mhttp/callback/BitmapCallbackHandler.java | 27 - .../mhttp/callback/CustomCallbackHandler.java | 34 -- .../mhttp/callback/FileCallbackHandler.java | 103 ---- .../callback/JsonArrayCallbackHandler.java | 37 -- .../mhttp/callback/JsonCallbackHandler.java | 48 -- .../mhttp/callback/TextCallbackHandler.java | 27 - .../wangchao/mhttp/executor/BACKGROUND.java | 17 - .../java/im/wangchao/mhttp/executor/MAIN.java | 21 - .../im/wangchao/mhttp/executor/SENDING.java | 27 - .../im/wangchao/mhttp/internal/Singleton.java | 25 - .../im/wangchao/mhttp/internal/Version.java | 21 - .../internal/cookie/ClearableCookieJar.java | 25 - .../internal/cookie/MemoryCookieJar.java | 60 --- .../internal/cookie/PersistentCookieJar.java | 133 ----- .../internal/cookie/cache/CookieCache.java | 38 -- .../cookie/cache/IdentifiableCookie.java | 74 --- .../internal/cookie/cache/SetCookieCache.java | 94 ---- .../cookie/persistence/CookiePersistor.java | 54 -- .../persistence/SerializableCookie.java | 146 ----- .../SharedPrefsCookiePersistor.java | 91 ---- .../internal/exception/ParserException.java | 17 - .../exception/ResponseFailException.java | 14 - .../interceptor/HttpLoggingInterceptor.java | 320 ----------- .../interceptor/MBridgeInterceptor.java | 36 -- .../mhttp/internal/log/LoggerImpl.java | 35 -- .../rxjava2/ResponseEnqueueObservable.java | 133 ----- .../rxjava2/ResponseExecuteObservable.java | 76 --- .../im/wangchao/mhttp/rxjava2/RxRequest.java | 233 -------- settings.gradle | 2 +- 53 files changed, 2 insertions(+), 4379 deletions(-) delete mode 100644 mhttp/build.gradle delete mode 100644 mhttp/gradle.properties delete mode 100644 mhttp/src/main/AndroidManifest.xml delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/AbsCallbackHandler.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/Accept.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/Android5SSL.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/BindApi.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/Callback.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/Converter.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/HTTPS.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/MHttp.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/Method.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/Request.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/RequestParams.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/Response.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/ThreadMode.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/URLInterceptor.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/body/FileBody.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/body/JSONBody.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/body/MediaTypeUtils.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/body/OctetStreamBody.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/body/ProgressRequestBody.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/callback/BinaryCallbackHandler.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/callback/BitmapCallbackHandler.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/callback/CustomCallbackHandler.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/callback/FileCallbackHandler.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/callback/JsonArrayCallbackHandler.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/callback/JsonCallbackHandler.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/callback/TextCallbackHandler.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/executor/BACKGROUND.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/executor/MAIN.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/executor/SENDING.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/internal/Singleton.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/internal/Version.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/ClearableCookieJar.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/MemoryCookieJar.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/PersistentCookieJar.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/cache/CookieCache.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/cache/IdentifiableCookie.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/cache/SetCookieCache.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/persistence/CookiePersistor.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/persistence/SerializableCookie.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/persistence/SharedPrefsCookiePersistor.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/internal/exception/ParserException.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/internal/exception/ResponseFailException.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/internal/interceptor/HttpLoggingInterceptor.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/internal/interceptor/MBridgeInterceptor.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/internal/log/LoggerImpl.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/rxjava2/ResponseEnqueueObservable.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/rxjava2/ResponseExecuteObservable.java delete mode 100644 mhttp/src/main/java/im/wangchao/mhttp/rxjava2/RxRequest.java diff --git a/app/build.gradle b/app/build.gradle index 2f2211d8..d6ccb59b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -170,7 +170,7 @@ dependencies { implementation project(":agendacalendarview") implementation "eu.szkolny:cafebar:5bf0c618de" implementation "eu.szkolny:material-about-library:0534abf316" - implementation project(":mhttp") + implementation "eu.szkolny:mhttp:af4b62e6e9" implementation "eu.szkolny:nachos:0e5dfcaceb" //implementation project(":Navigation") implementation project(":szkolny-font") diff --git a/mhttp/build.gradle b/mhttp/build.gradle deleted file mode 100644 index a17c5b48..00000000 --- a/mhttp/build.gradle +++ /dev/null @@ -1,51 +0,0 @@ -apply plugin: 'com.android.library' - -android { - compileSdkVersion setup.compileSdk - - defaultConfig { - minSdkVersion 9 - targetSdkVersion setup.targetSdk - consumerProguardFiles 'proguard-rules.pro' - versionCode 1 - versionName PROJ_VERSION - javaCompileOptions { - annotationProcessorOptions { - includeCompileClasspath = true - } - } - } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - debugMinify { - debuggable = true - minifyEnabled = true - proguardFiles 'proguard-android.txt' - } - } - packagingOptions { - exclude 'META-INF/services/javax.annotation.processing.Processor' - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - lintOptions { - textReport true - textOutput 'stdout' - } -} - -dependencies { - compileOnly "androidx.appcompat:appcompat:${versions.appcompat}" - compileOnly 'io.reactivex.rxjava2:rxjava:2.1.3' - api 'com.squareup.okhttp3:okhttp:3.12.0' - api 'com.google.code.gson:gson:2.8.5' - //api deps.mhttpannotations -// implementation project(':mhttp-annotations') -} - -//apply from: 'https://raw.githubusercontent.com/motcwang/Utils/master/bintray-publish/bintray.gradle' \ No newline at end of file diff --git a/mhttp/gradle.properties b/mhttp/gradle.properties deleted file mode 100644 index 58145d18..00000000 --- a/mhttp/gradle.properties +++ /dev/null @@ -1,31 +0,0 @@ -# Project-wide Gradle settings. - -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. - -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html - -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -# Default value: -Xmx10248m -XX:MaxPermSize=256m -# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 - -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true -PROJ_GROUP=im.wangchao -PROJ_VERSION=1.10.1 -PROJ_NAME=mhttp -PROJ_WEBSITEURL=http://wangchao.im/2015/11/22/mhttpadapter-post.html -PROJ_ISSUETRACKERURL=https://github.com/motcwang/MHttp/issues -PROJ_VCSURL=git@github.com:motcwang/MHttp.git -PROJ_DESCRIPTION= -PROJ_ARTIFACTID=mhttp -PROJ_PACKAGING=aar - -DEVELOPER_ID=mot -DEVELOPER_NAME=Wang Chao -DEVELOPER_EMAIL=magician.of.technique@aliyun.com \ No newline at end of file diff --git a/mhttp/src/main/AndroidManifest.xml b/mhttp/src/main/AndroidManifest.xml deleted file mode 100644 index 1c8f0a8f..00000000 --- a/mhttp/src/main/AndroidManifest.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - diff --git a/mhttp/src/main/java/im/wangchao/mhttp/AbsCallbackHandler.java b/mhttp/src/main/java/im/wangchao/mhttp/AbsCallbackHandler.java deleted file mode 100644 index 32d94c89..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/AbsCallbackHandler.java +++ /dev/null @@ -1,256 +0,0 @@ -package im.wangchao.mhttp; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import android.text.TextUtils; -import android.util.Log; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -import im.wangchao.mhttp.internal.exception.ParserException; -import im.wangchao.mhttp.internal.exception.ResponseFailException; -import okhttp3.Call; -import okhttp3.internal.Util; - -import static im.wangchao.mhttp.Response.IO_EXCEPTION_CODE; - -/** - *

Description : AbsResponseHandler. - * Callback lifecycle as follow: - * onStart() - * ------------------------------------------------------- - * | - * | - * is canceled --- Y --- onCancel() - * | - * N - * | - * onFinish() - * | - * | - * is successful --- N --- onFailure() ------------------ - * | | - * Y | - * | | - * backgroundParser() --is download-- onProgress() | - * | | | - * | | | - * onSuccess() onSuccess() | - * | | | - * | | | - * --------------------------------------------------------- - * onFinally() - *

- *

Author : wangchao.

- *

Date : 15/8/17.

- *

Time : 下午5:56.

- */ -public abstract class AbsCallbackHandler implements Callback, Converter{ - private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool(Util.threadFactory("OkHttp", false)); - - public final static String DEFAULT_CHARSET = "UTF-8"; - - private Request request; - private String responseCharset = DEFAULT_CHARSET; - private boolean isFinished; - private boolean isCanceled; - - private Executor mExecutor; - - /** Working thread depends on {@link #mExecutor}, default UI. */ - public abstract void onSuccess(Parser_Type data, Response response); - /** Working thread depends on {@link #mExecutor}, default UI. */ - public abstract void onFailure(Response response, Throwable throwable); - /** Work on the request thread, that is okhttp thread. */ - @Deprecated - public Parser_Type backgroundParser(Response response) throws Exception{ - return null; - } - /** Work on the request thread, that is okhttp thread. */ - @Override public Parser_Type apply(Response response) throws Exception { - return backgroundParser(response); - } - - /** Working thread depends on {@link #mExecutor}, default UI. */ - public void onStart(){} - /** Working thread depends on {@link #mExecutor}, default UI. */ - public void onCancel(){} - /** Working thread depends on {@link #mExecutor}, default UI. */ - public void onProgress(long bytesWritten, long bytesTotal){} - /** Working thread depends on {@link #mExecutor}, default UI. */ - public void onUploadProgress(int bytesWritten, int bytesTotal){} - /** Working thread depends on {@link #mExecutor}, default UI. */ - public void onFinish(){} - /** Working thread depends on {@link #mExecutor}, default UI. */ - public void onFinally(Response response){} - - - @Override final public void onFailure(@NonNull Call call, @NonNull IOException e) { - if (call.isCanceled()){ - sendCancelEvent(); - return; - } - sendFinishEvent(); - - final Request req = request; - Response response = Response.error(req, - IO_EXCEPTION_CODE, - e.getMessage()); - - sendFailureEvent(response, e); - sendFinallyEvent(response); - } - - @Override final public void onResponse(@NonNull Call call, @NonNull okhttp3.Response response) throws IOException { - if (call.isCanceled()){ - response.close(); - sendCancelEvent(); - return; - } - sendFinishEvent(); - - final Request req = request; - Response okResponse; - if (response.isSuccessful() || response.isRedirect() - || req.allowedErrorCodes().contains(response.code())) { - try { - okResponse = Response.newResponse(req, response); - Parser_Type data = apply(okResponse); - sendSuccessEvent(data, okResponse); - } catch (Exception e) { - sendFailureEvent(okResponse = Response.newResponse(req, response), e); - } - } else { - sendFailureEvent(okResponse = Response.newResponse(req, response), new ResponseFailException()); - } - // todo response.close() - sendFinallyEvent(okResponse); - } - - public AbsCallbackHandler(){} - - @Override public void initialize(Request request){ - isFinished = false; - isCanceled = false; - this.request = request; - this.mExecutor = request.callbackExecutor(); - if (this.mExecutor == null){ - this.mExecutor = request.callbackThreadMode().executor(); - } - } - - public final boolean isFinished(){ - return isFinished; - } - - /** - * Sets the charset for the response string. If not set, the default is UTF-8. - */ - public final void setCharset(@NonNull final String charset) { - this.responseCharset = charset; - } - - /** - * subclass can override this method to change charset. - */ - public String charset() { - return TextUtils.isEmpty(responseCharset) ? DEFAULT_CHARSET : responseCharset; - } - - /** - * @return request accept - */ - @Override public String accept(){ - return Accept.EMPTY; - } - - protected final void print(String message){ - Log.d(AbsCallbackHandler.class.getSimpleName(), message); - } - - @Nullable protected final String byteArrayToString(byte[] bytes){ - try { - return bytes == null ? null : new String(bytes, charset()); - } catch (UnsupportedEncodingException e) { - return null; - } - } - - protected final Request getRequest(){ - return this.request; - } - - public final void sendUploadProgressEvent(final int bytesWritten, final int bytesTotal) { - execute(()->{ - try { - onUploadProgress(bytesWritten, bytesTotal); - } catch (Throwable t) { - //Silent - } - }); - } - - public final void sendProgressEvent(final long bytesWritten, final long bytesTotal) { - execute(()->{ - try { - onProgress(bytesWritten, bytesTotal); - } catch (Throwable t) { - //Silent - } - }); - } - - /*package*/ final void sendSuccessEvent(final Parser_Type data, final Response response) { - execute(() -> onSuccess(data, response)); - } - - /*package*/ final void sendFailureEvent(final Response response, @Nullable final Throwable throwable) { - execute(() -> onFailure(response, throwable)); - } - - /*package*/ final void sendStartEvent() { - if (request.callbackThreadMode() == ThreadMode.BACKGROUND){ - DEFAULT_EXECUTOR_SERVICE.execute(this::onStart); - } else { - execute(this::onStart); - } - } - - /*package*/ final void sendFinishEvent() { - execute(() -> { - AbsCallbackHandler.this.isFinished = true; - onFinish(); - }); - } - - /*package*/ final void sendFinallyEvent(final Response response) { - execute(() -> onFinally(response)); - } - - /*package*/ final synchronized void sendCancelEvent() { - if (isCanceled){ - return; - } - execute(() -> { - AbsCallbackHandler.this.isCanceled = true; - onCancel(); - }); - } - - private void execute(Runnable command){ - if (mExecutor == null || threadInterrupted()){ - return; - } - - mExecutor.execute(command); - } - - private boolean threadInterrupted(){ - return Thread.currentThread().isInterrupted(); - } - -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/Accept.java b/mhttp/src/main/java/im/wangchao/mhttp/Accept.java deleted file mode 100644 index 161d227e..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/Accept.java +++ /dev/null @@ -1,33 +0,0 @@ -package im.wangchao.mhttp; - -import androidx.annotation.StringDef; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - *

Description : Accept.

- *

Author : wangchao.

- *

Date : 16/4/25.

- *

Time : 上午11:06.

- */ -public interface Accept { - String EMPTY = ""; - String ACCEPT_JSON = "application/json;charset=utf-8"; - String ACCEPT_TEXT = "text/html;charset=utf-8"; - String ACCEPT_DATA = "application/octet-stream"; - String ACCEPT_IMAGE = "image/png,image/jpeg,image/*"; - String ACCEPT_FILE = "application/octet-stream"; - - @Retention(RetentionPolicy.SOURCE) - @StringDef({ - Accept.EMPTY, - Accept.ACCEPT_JSON, - Accept.ACCEPT_TEXT, - Accept.ACCEPT_DATA, - Accept.ACCEPT_IMAGE, - Accept.ACCEPT_FILE - }) - public @interface $Accept { - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/Android5SSL.java b/mhttp/src/main/java/im/wangchao/mhttp/Android5SSL.java deleted file mode 100644 index 4ddbc6de..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/Android5SSL.java +++ /dev/null @@ -1,149 +0,0 @@ -package im.wangchao.mhttp; - -import android.os.Build; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.Socket; -import java.net.UnknownHostException; -import java.security.GeneralSecurityException; -import java.util.Arrays; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.X509TrustManager; - -/** - *

Description : Android5SSL.

- *

Author : wangchao.

- *

Date : 2018/3/19.

- *

Time : 上午11:09.

- */ -/*package*/ class Android5SSL extends SSLSocketFactory { - private SSLSocketFactory defaultFactory; - // Android 5.0+ (API level21) provides reasonable default settings - // but it still allows SSLv3 - // https://developer.android.com/about/versions/android-5.0-changes.html#ssl - static String protocols[] = null, cipherSuites[] = null; - - static { - try { - SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket(); - if (socket != null) { - /* set reasonable protocol versions */ - // - enable all supported protocols (enables TLSv1.1 and TLSv1.2 on Android <5.0) - // - remove all SSL versions (especially SSLv3) because they're insecure now - List protocols = new LinkedList<>(); - for (String protocol : socket.getSupportedProtocols()) - if (!protocol.toUpperCase().contains("SSL")) - protocols.add(protocol); - Android5SSL.protocols = protocols.toArray(new String[protocols.size()]); - /* set up reasonable cipher suites */ - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - // choose known secure cipher suites - List allowedCiphers = Arrays.asList( - // TLS 1.2 - "TLS_RSA_WITH_AES_256_GCM_SHA384", - "TLS_RSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", - "TLS_ECHDE_RSA_WITH_AES_128_GCM_SHA256", - // maximum interoperability - "TLS_RSA_WITH_3DES_EDE_CBC_SHA", - "TLS_RSA_WITH_AES_128_CBC_SHA", - // additionally - "TLS_RSA_WITH_AES_256_CBC_SHA", - "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", - "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"); - List availableCiphers = Arrays.asList(socket.getSupportedCipherSuites()); - // take all allowed ciphers that are available and put them into preferredCiphers - HashSet preferredCiphers = new HashSet<>(allowedCiphers); - preferredCiphers.retainAll(availableCiphers); - /* For maximum security, preferredCiphers should *replace* enabled ciphers (thus disabling - * ciphers which are enabled by default, but have become unsecure), but I guess for - * the security level of DAVdroid and maximum compatibility, disabling of insecure - * ciphers should be a server-side task */ - // add preferred ciphers to enabled ciphers - HashSet enabledCiphers = preferredCiphers; - enabledCiphers.addAll(new HashSet<>(Arrays.asList(socket.getEnabledCipherSuites()))); - Android5SSL.cipherSuites = enabledCiphers.toArray(new String[enabledCiphers.size()]); - } - } - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - public Android5SSL(X509TrustManager tm) { - try { - SSLContext sslContext = SSLContext.getInstance("TLS"); - sslContext.init(null, (tm != null) ? new X509TrustManager[]{tm} : null, null); - defaultFactory = sslContext.getSocketFactory(); - } catch (GeneralSecurityException e) { - throw new AssertionError(); // The system has no TLS. Just give up. - } - } - - private void upgradeTLS(SSLSocket ssl) { - // Android 5.0+ (API level21) provides reasonable default settings - // but it still allows SSLv3 - // https://developer.android.com/about/versions/android-5.0-changes.html#ssl - if (protocols != null) { - ssl.setEnabledProtocols(protocols); - } - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && cipherSuites != null) { - ssl.setEnabledCipherSuites(cipherSuites); - } - } - - @Override public String[] getDefaultCipherSuites() { - return cipherSuites; - } - - @Override public String[] getSupportedCipherSuites() { - return cipherSuites; - } - - @Override public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { - Socket ssl = defaultFactory.createSocket(s, host, port, autoClose); - if (ssl instanceof SSLSocket) - upgradeTLS((SSLSocket) ssl); - return ssl; - } - - @Override public Socket createSocket(String host, int port) throws IOException, UnknownHostException { - Socket ssl = defaultFactory.createSocket(host, port); - if (ssl instanceof SSLSocket) - upgradeTLS((SSLSocket) ssl); - return ssl; - } - - @Override public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException { - Socket ssl = defaultFactory.createSocket(host, port, localHost, localPort); - if (ssl instanceof SSLSocket) - upgradeTLS((SSLSocket) ssl); - return ssl; - } - - @Override public Socket createSocket(InetAddress host, int port) throws IOException { - Socket ssl = defaultFactory.createSocket(host, port); - if (ssl instanceof SSLSocket) - upgradeTLS((SSLSocket) ssl); - return ssl; - } - - @Override public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { - Socket ssl = defaultFactory.createSocket(address, port, localAddress, localPort); - if (ssl instanceof SSLSocket) - upgradeTLS((SSLSocket) ssl); - return ssl; - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/BindApi.java b/mhttp/src/main/java/im/wangchao/mhttp/BindApi.java deleted file mode 100644 index 03f26855..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/BindApi.java +++ /dev/null @@ -1,28 +0,0 @@ -package im.wangchao.mhttp; - - -import android.util.Log; - -/** - *

Description : BindApi.

- *

Author : wangchao.

- *

Date : 15/10/19.

- *

Time : 上午8:23.

- */ -final class BindApi { - /** HttpProcessor.SUFFIX */ - private static final String SUFFIX = "_HttpBinder"; - - @SuppressWarnings("unchecked") public static T bind(Class type) { - String name = type.getName() + SUFFIX; - T obj = null; - try { - obj = (T)Class.forName(name).newInstance(); - } catch (Exception e) { - Log.e(BindApi.class.getSimpleName(), e.getMessage(), e); - } - return obj; - } - - -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/Callback.java b/mhttp/src/main/java/im/wangchao/mhttp/Callback.java deleted file mode 100644 index fa617fe2..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/Callback.java +++ /dev/null @@ -1,40 +0,0 @@ -package im.wangchao.mhttp; - -import java.io.IOException; - -import okhttp3.Call; -import okhttp3.Response; - -/** - *

Description : OkCallback.

- *

Author : wangchao.

- *

Date : 16/6/3.

- *

Time : 上午10:16.

- */ -public interface Callback extends okhttp3.Callback { - - Callback EMPTY = new Callback() { - @Override public void initialize(Request request) {} - - @Override public String accept() { - return Accept.EMPTY; - } - - @Override public void onFailure(Call call, IOException e) {} - - @Override public void onResponse(Call call, Response response) throws IOException { - response.close(); - } - }; - - /** - * Initialize the callback. - */ - void initialize(Request request); - - /** - * Request accept. - */ - String accept(); - -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/Converter.java b/mhttp/src/main/java/im/wangchao/mhttp/Converter.java deleted file mode 100644 index c75bf3f0..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/Converter.java +++ /dev/null @@ -1,12 +0,0 @@ -package im.wangchao.mhttp; - -/** - *

Description : Converter.

- *

Author : wangchao.

- *

Date : 2018/3/20.

- *

Time : 下午10:26.

- */ -public interface Converter { - - R apply(T t) throws Exception; -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/HTTPS.java b/mhttp/src/main/java/im/wangchao/mhttp/HTTPS.java deleted file mode 100644 index c485086f..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/HTTPS.java +++ /dev/null @@ -1,179 +0,0 @@ -package im.wangchao.mhttp; - -import java.io.InputStream; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; - -import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509TrustManager; - -import okhttp3.OkHttpClient; -import okhttp3.internal.Util; - -/** - *

Description : HTTPS.

- *

Author : wangchao.

- *

Date : 16/9/2.

- *

Time : 下午3:58.

- */ -/*package*/ final class HTTPS { - - // 信任所有证书的 TrustManager - private static X509TrustManager TrustAllCertificate = new X509TrustManager() { - @Override public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { - } - - @Override public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { - } - - @Override public java.security.cert.X509Certificate[] getAcceptedIssuers() { - return new java.security.cert.X509Certificate[]{}; - } - }; - - /** - * Trust all certificate for debug - */ - /*package*/ static void trustAllCertificate(OkHttpClient.Builder builder) { - builder.sslSocketFactory(new Android5SSL(TrustAllCertificate), TrustAllCertificate); - } - - /** - * Set Certificate - */ - /*package*/ static void setCertificates(OkHttpClient.Builder builder, - InputStream... certificates) throws Exception { - setCertificates(builder, null, certificates, null, null); - } - - /** - * Set Certificate - */ - /*package*/ static void setCertificates(OkHttpClient.Builder builder, - X509TrustManager trustManager, - InputStream bksFile, - String password) throws Exception { - setCertificates(builder, trustManager, null, bksFile, password); - } - - /** - * Set Certificate - */ - /*package*/ static void setCertificates(OkHttpClient.Builder builder, - InputStream[] certificates, - InputStream bksFile, - String password) throws Exception { - setCertificates(builder, null, certificates, bksFile, password); - } - - /** - * Set Certificate - */ - /*package*/ static void setCertificates(OkHttpClient.Builder builder, - X509TrustManager trustManager, - InputStream[] certificates, - InputStream bksFile, - String password) throws Exception { - TrustManager[] trustManagers = prepareTrustManager(certificates); - KeyManager[] keyManagers = prepareKeyManager(bksFile, password); - - X509TrustManager manager; - if (trustManager != null) { - manager = trustManager; - } else if (trustManagers != null) { - manager = chooseTrustManager(trustManagers); - } else { - manager = TrustAllCertificate; - } - - // 创建TLS类型的SSLContext对象, that uses our finalTrustManager - SSLContext sslContext = SSLContext.getInstance("TLS"); - // 用上面得到的trustManagers初始化SSLContext,这样sslContext就会信任keyStore中的证书 - // 第一个参数是授权的密钥管理器,用来授权验证,比如授权自签名的证书验证。第二个是被授权的证书管理器,用来验证服务器端的证书 - sslContext.init(keyManagers, new TrustManager[]{manager}, new SecureRandom()); - builder.sslSocketFactory(sslContext.getSocketFactory(), manager); - } - - /*package*/ static TrustManager[] prepareTrustManager(InputStream... certificates) throws Exception { - if (certificates == null || certificates.length <= 0) return null; - - CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); - // 创建一个默认类型的KeyStore,存储我们信任的证书 - KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - keyStore.load(null); - int index = 0; - for (InputStream certificate : certificates) { - String certificateAlias = Integer.toString(index++); - keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate)); - Util.closeQuietly(certificate); - } - - TrustManagerFactory trustManagerFactory = TrustManagerFactory. - getInstance(TrustManagerFactory.getDefaultAlgorithm()); - //用我们之前的keyStore实例初始化TrustManagerFactory,使TrustManagerFactory信任keyStore中的证书 - trustManagerFactory.init(keyStore); - return trustManagerFactory.getTrustManagers(); - } - - /*package*/ static KeyManager[] prepareKeyManager(InputStream bksFile, String password) throws Exception{ - if (bksFile == null || password == null) return null; - - KeyStore clientKeyStore = KeyStore.getInstance("BKS"); - clientKeyStore.load(bksFile, password.toCharArray()); - KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - keyManagerFactory.init(clientKeyStore, password.toCharArray()); - return keyManagerFactory.getKeyManagers(); - } - - /*package*/ static X509TrustManager chooseTrustManager(TrustManager[] trustManagers) { - for (TrustManager trustManager : trustManagers) { - if (trustManager instanceof X509TrustManager) { - return (X509TrustManager) trustManager; - } - } - return null; - } - - /* X509TrustManager */ - /*package*/ static class MyTrustManager implements X509TrustManager { - private X509TrustManager defaultTrustManager; - private X509TrustManager localTrustManager; - - /*package*/ MyTrustManager(X509TrustManager localTrustManager) throws NoSuchAlgorithmException, KeyStoreException { - TrustManagerFactory var4 = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - var4.init((KeyStore) null); - defaultTrustManager = chooseTrustManager(var4.getTrustManagers()); - this.localTrustManager = localTrustManager; - } - - @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { -// try { -// defaultTrustManager.checkClientTrusted(chain, authType); -// } catch (CertificateException e) { -// localTrustManager.checkClientTrusted(chain, authType); -// } - } - - @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { - try { - defaultTrustManager.checkServerTrusted(chain, authType); - } catch (CertificateException e) { - localTrustManager.checkServerTrusted(chain, authType); - } - } - - - @Override public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[0]; - } - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/MHttp.java b/mhttp/src/main/java/im/wangchao/mhttp/MHttp.java deleted file mode 100644 index af46229b..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/MHttp.java +++ /dev/null @@ -1,252 +0,0 @@ -package im.wangchao.mhttp; - -import android.content.Context; -import android.os.Build; -import android.os.StatFs; -import androidx.annotation.NonNull; - -import java.io.File; -import java.io.InputStream; -import java.net.URL; -import java.util.concurrent.TimeUnit; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.X509TrustManager; - -import im.wangchao.mhttp.internal.interceptor.HttpLoggingInterceptor; -import im.wangchao.mhttp.internal.interceptor.MBridgeInterceptor; -import im.wangchao.mhttp.internal.log.LoggerImpl; -import okhttp3.Cache; -import okhttp3.Call; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; - -/** - *

Description : MHttp.

- *

Author : wangchao.

- *

Date : 16/6/2.

- *

Time : 上午8:40.

- */ -public final class MHttp { - private static volatile MHttp instance; - - private OkHttpClient.Builder mOkBuilder; - private OkHttpClient mInnerClient; - private URLInterceptor mURLInterceptor; - private final HttpLoggingInterceptor mLoggingInterceptor = new HttpLoggingInterceptor(LoggerImpl.instance.get()); - - public static MHttp instance(){ - if (instance == null) { - synchronized (MHttp.class){ - instance = new MHttp(); - } - } - return instance; - } - - /** - * Create annotation api - */ - public static T create(Class api){ - return BindApi.bind(api); - } - - /** - * OkHttpClient - */ - public MHttp customOkHttpClient(@NonNull OkHttpClient client){ - mOkBuilder = client.newBuilder() - .addInterceptor(MBridgeInterceptor.instance.get()); - return this; - } - - /** - * Set logging level - */ - public MHttp loggingLevel(HttpLoggingInterceptor.Level level){ - mLoggingInterceptor.setLevel(level); - LoggerImpl.instance.get().setLevel(level); - if (!mOkBuilder.interceptors().contains(mLoggingInterceptor)) { - mOkBuilder.addInterceptor(mLoggingInterceptor); - } - return this; - } - - /** - * Set cache Dir - */ - public MHttp cache(Context context, String dirName) { - File cache = new File(context.getApplicationContext().getCacheDir(), dirName); - if (!cache.exists()) { - //noinspection ResultOfMethodCallIgnored - cache.mkdirs(); - } - long size = 5 * 1024 * 1024; - try { - StatFs statFs = new StatFs(cache.getAbsolutePath()); - long count, blockSize; - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1){ - count = statFs.getBlockCountLong(); - blockSize = statFs.getBlockSizeLong(); - } else { - count = statFs.getBlockCount(); - blockSize = statFs.getBlockSize(); - } - long available = count * blockSize; - // Target 2% of the total space. - size = available / 50; - } catch (IllegalArgumentException ignored) { - } - // Bound inside min/max size for disk cache. - size = Math.max(Math.min(size, size * 10), size); - - mOkBuilder.cache(new Cache(cache, size)); - return this; - } - - /** - * Set connect, read and write time with {@link TimeUnit#SECONDS} - */ - public MHttp timeout(int timeout){ - timeout(timeout, TimeUnit.SECONDS); - return this; - } - - public MHttp timeout(int timeout, TimeUnit unit){ - connectTimeout(timeout, unit); - readTimeout(timeout, unit); - writeTimeout(timeout, unit); - return this; - } - - public MHttp connectTimeout(long timeout, TimeUnit unit){ - mOkBuilder.connectTimeout(timeout, unit); - return this; - } - - public MHttp readTimeout(long timeout, TimeUnit unit){ - mOkBuilder.readTimeout(timeout, unit); - return this; - } - - public MHttp writeTimeout(long timeout, TimeUnit unit){ - mOkBuilder.writeTimeout(timeout, unit); - return this; - } - - public MHttp setURLInterceptor(URLInterceptor interceptor){ - this.mURLInterceptor = interceptor; - return this; - } - - /** - * Trust all certificate for debug - */ - public MHttp trustAllCertificate(){ - HTTPS.trustAllCertificate(mOkBuilder); - return this; - } - - /** - * Set Certificate - */ - public MHttp setCertificates(InputStream... certificates){ - return setCertificates(certificates, null, null); - } - - /** - * Set Certificate - */ - public MHttp setCertificates(X509TrustManager trustManager, InputStream bksFile, String password) { - try { - HTTPS.setCertificates(mOkBuilder, trustManager, null, bksFile, password); - } catch (Exception e) { - throw new RuntimeException(e); - } - return this; - } - - /** - * Set Certificate - */ - public MHttp setCertificates(InputStream[] certificates, InputStream bksFile, String password) { - try { - HTTPS.setCertificates(mOkBuilder, null, certificates, bksFile, password); - } catch (Exception e) { - throw new RuntimeException(e); - } - return this; - } - - public MHttp hostnameVerifier(HostnameVerifier hostnameVerifier){ - mOkBuilder.hostnameVerifier(hostnameVerifier); - return this; - } - - /** - * @return Current client. - */ - public OkHttpClient client(){ - if (mOkBuilder == null){ - throw new IllegalArgumentException("OkHttpClient cannot be null, please call the MHttp#client(OkHttpClient client) method first."); - } - if (mInnerClient == null){ - mInnerClient = mOkBuilder.build(); - } - return mInnerClient; - } - - /** - * Cancel all request. - */ - public MHttp cancelAll(){ - client().dispatcher().cancelAll(); - return this; - } - - /** - * Cancel request with {@code tag} - */ - public MHttp cancel(Object tag){ - for (Call call : client().dispatcher().queuedCalls()) { - if (tag.equals(call.request().tag())) { - call.cancel(); - } - } - for (Call call : client().dispatcher().runningCalls()) { - if (tag.equals(call.request().tag())) { - call.cancel(); - } - } - return this; - } - - /*package*/ String proceedURL(String url){ - if (mURLInterceptor != null){ - return mURLInterceptor.interceptor(url); - } - return url; - } - - /*package*/ HttpUrl proceedURL(HttpUrl url){ - if (mURLInterceptor != null){ - return mURLInterceptor.interceptor(url); - } - return url; - } - - /*package*/ URL proceedURL(URL url){ - if (mURLInterceptor != null){ - return mURLInterceptor.interceptor(url); - } - return url; - } - - //@private - private MHttp(){ - //default instance - mOkBuilder = new OkHttpClient.Builder() - .addInterceptor(MBridgeInterceptor.instance.get()); - } - -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/Method.java b/mhttp/src/main/java/im/wangchao/mhttp/Method.java deleted file mode 100644 index f7453aab..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/Method.java +++ /dev/null @@ -1,25 +0,0 @@ -package im.wangchao.mhttp; - -import androidx.annotation.StringDef; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - *

Description : Method.

- *

Author : wangchao.

- *

Date : 16/3/8.

- *

Time : 下午4:08.

- */ -public interface Method { - String POST = "POST"; - String GET = "GET"; - String HEAD = "HEAD"; - String DELETE = "DELETE"; - String PUT = "PUT"; - String PATCH = "PATCH"; - - @Retention(RetentionPolicy.SOURCE) - @StringDef({Method.POST, Method.GET, Method.HEAD, Method.DELETE, Method.PUT, Method.PATCH}) - @interface MethodType{} -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/Request.java b/mhttp/src/main/java/im/wangchao/mhttp/Request.java deleted file mode 100644 index 426b0eab..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/Request.java +++ /dev/null @@ -1,503 +0,0 @@ -package im.wangchao.mhttp; - -import androidx.annotation.NonNull; -import android.util.Pair; -import android.util.Log; - -import com.google.gson.JsonObject; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Executor; - -import im.wangchao.mhttp.body.JSONBody; -import im.wangchao.mhttp.body.MediaTypeUtils; -import okhttp3.CacheControl; -import okhttp3.Call; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.RequestBody; -import okio.Buffer; -import okio.BufferedSink; - -/** - *

Description : MRequest.

- *

Author : wangchao.

- *

Date : 16/6/2.

- *

Time : 下午4:16.

- */ -public final class Request { - public static Builder builder(){ - return new Builder(); - } - - private final okhttp3.Request mRawRequest; - private final RequestParams mRequestParams; - private final Callback mCallback; - private final MediaType mMediaType; - private final Executor mExecutor; - private final ThreadMode mThreadMode; - private final JsonObject mJsonBody; - private final okhttp3.OkHttpClient mOkHttpClient; - private final List mAllowedErrorCodes; - private final String mTextBody; - - private okhttp3.Call mRawCall; - - private Request(Builder builder){ - mRawRequest = builder.mRawRequest; - mRequestParams = builder.mRequestParams; - mCallback = builder.mCallback; - mMediaType = builder.mMediaType; - mExecutor = builder.mExecutor; - mThreadMode = builder.mThreadMode; - mJsonBody = builder.mJsonBody; - mOkHttpClient = builder.mOkHttpClient; - mAllowedErrorCodes = builder.mAllowedErrorCodes; - mTextBody = builder.mTextBody; - } - - public okhttp3.Request raw() { - return mRawRequest; - } - - public HttpUrl url() { - return mRawRequest.url(); - } - - public String method() { - return mRawRequest.method(); - } - - public Headers headers() { - return mRawRequest.headers(); - } - - public String header(String name) { - return mRawRequest.header(name); - } - - public List headers(String name) { - return mRawRequest.headers(name); - } - - public RequestBody body() { - return mRawRequest.body(); - } - - public String bodyToString(){ - try { - final Buffer buffer = new Buffer(); - body().writeTo(buffer); - return buffer.readUtf8(); - } catch (final Exception e) { - return "did not work. "+e.getMessage(); - } - } - - public Object tag() { - return mRawRequest.tag(); - } - - public Builder newBuilder() { - return new Builder(this); - } - - public Callback callback() { - return mCallback; - } - - public JsonObject jsonBody() { - return mJsonBody; - } - - public String textBody() { - return mTextBody; - } - - public OkHttpClient okHttpClient() { - return mOkHttpClient; - } - - public List allowedErrorCodes() { - return mAllowedErrorCodes; - } - - /** - * Returns the cache control directives for this response. This is never null, even if this - * response contains no {@code Cache-Control} header. - */ - public CacheControl cacheControl() { - return mRawRequest.cacheControl(); - } - - public boolean isHttps() { - return mRawRequest.isHttps(); - } - - /** - * The executor used for {@link Callback} methods on which thread work. - */ - public Executor callbackExecutor() { - return mExecutor; - } - - /** - * {@link Callback} methods on which thread work. - */ - public ThreadMode callbackThreadMode() { - return mThreadMode; - } - - public RequestParams requestParams(){ - return mRequestParams; - } - - /** - * Send the async request. - */ - public Request enqueue(){ - Callback callback = callback(); - callback.initialize(this); - if (callback instanceof AbsCallbackHandler){ - ((AbsCallbackHandler) callback).sendStartEvent(); - } - rawCall().enqueue(callback); - return this; - } - - /** - * Send the sync request. - */ - public Response execute() throws IOException { - return Response.newResponse(this, rawCall().execute()); - } - - /** - * Cancel this request - */ - public Request cancel(){ - if (rawCall().isCanceled()){ - return this; - } - rawCall().cancel(); - return this; - } - - private Call rawCall(){ - if (mRawCall == null){ - OkHttpClient client; - if (mOkHttpClient == null) { - client = MHttp.instance().client(); - } - else { - client = mOkHttpClient; - } - mRawCall = client.newCall(raw()); - } - return mRawCall; - } - - @Override public String toString() { - return mRawRequest.toString(); - } - - public static class Builder { - private static final String TAG = Builder.class.getSimpleName(); - - okhttp3.Request mRawRequest; - okhttp3.Request.Builder mRawBuilder; - RequestParams mRequestParams; - Callback mCallback; - String mMethod; - MediaType mMediaType; - Executor mExecutor; - ThreadMode mThreadMode; - JsonObject mJsonBody; - OkHttpClient mOkHttpClient; - List mAllowedErrorCodes; - String mTextBody; - - public Builder() { - mCallback = Callback.EMPTY; - mMethod = Method.GET; - mRawBuilder = new okhttp3.Request.Builder(); - mRequestParams = new RequestParams(); - mThreadMode = ThreadMode.BACKGROUND; - mJsonBody = null; - mOkHttpClient = null; - mAllowedErrorCodes = new ArrayList<>(); - mTextBody = null; - } - - private Builder(Request request) { - mCallback = request.mCallback; - mMethod = request.method(); - mRequestParams = request.mRequestParams; - mRawBuilder = request.mRawRequest.newBuilder(); - mExecutor = request.mExecutor; - mThreadMode = request.mThreadMode; - mMediaType = request.mMediaType; - mJsonBody = request.mJsonBody; - mOkHttpClient = request.mOkHttpClient; - mAllowedErrorCodes = request.mAllowedErrorCodes; - mTextBody = request.mTextBody; - } - - public Builder url(HttpUrl url) { - mRawBuilder.url(MHttp.instance().proceedURL(url)); - return this; - } - - public Builder url(String url) { - mRawBuilder.url(MHttp.instance().proceedURL(url)); - return this; - } - - public Builder url(URL url) { - mRawBuilder.url(MHttp.instance().proceedURL(url)); - return this; - } - - public Builder header(String name, String value) { - mRawBuilder.header(name, value); - return this; - } - - public Builder addHeader(String name, String value) { - mRawBuilder.addHeader(name, value); - return this; - } - - public Builder removeHeader(String name) { - mRawBuilder.removeHeader(name); - return this; - } - - public Builder headers(Headers headers) { - mRawBuilder.headers(headers); - return this; - } - - public Builder cacheControl(CacheControl cacheControl) { - mRawBuilder.cacheControl(cacheControl); - return this; - } - - public Builder withClient(OkHttpClient okHttpClient) { - mOkHttpClient = okHttpClient; - return this; - } - - public Builder get() { - return method(Method.GET); - } - - public Builder head() { - return method(Method.HEAD); - } - - public Builder post() { - return method(Method.POST); - } - - public Builder postJson() { - return method(Method.POST).contentType(MediaTypeUtils.APPLICATION_JSON); - } - - public Builder delete() { - return method(Method.DELETE); - } - - public Builder put() { - return method(Method.PUT); - } - - public Builder patch() { - return method(Method.PATCH); - } - - public Builder setJsonBody(JsonObject jsonBody) { - mJsonBody = jsonBody; - return method(Method.POST).contentType(MediaTypeUtils.APPLICATION_JSON); - } - - public Builder setTextBody(String textBody, String mediaType) { - mTextBody = textBody; - return method(Method.POST).contentType(mediaType); - } - - public Builder allowErrorCode(int code) { - mAllowedErrorCodes.add(code); - return this; - } - - /** - * Simple to add request parameter - */ - public Builder addParameter(String key, Object value){ - mRequestParams.put(key, value); - return this; - } - - /** - * Simple to add request parameter - */ - public Builder addParameter(String key, InputStream stream, String name){ - mRequestParams.put(key, stream, name); - return this; - } - - /** - * Simple to add request parameter - */ - public Builder addParameter(String key, InputStream stream, String name, String contentType){ - mRequestParams.put(key, stream, name, contentType); - return this; - } - - /** - * Simple to add request parameter - */ - public Builder addParameter(String key, File file, String contentType){ - try { - mRequestParams.put(key, file, contentType); - } catch (FileNotFoundException e) { - Log.e(TAG, e.getMessage(), e); - } - return this; - } - - public Builder requestParams(RequestParams params) { - if (params != null){ - mRequestParams = params; - } - return this; - } - - public Builder addParams(List> params) { - if (params != null){ - mRequestParams.put(params); - } - return this; - } - - public Builder method(@NonNull String method) { - this.mMethod = method; - return this; - } - - public Builder tag(Object tag) { - mRawBuilder.tag(tag); - return this; - } - - public Builder callback(@NonNull Callback callback){ - mCallback = callback; - return this; - } - - public Builder callbackExecutor(Executor executor){ - mExecutor = executor; - return this; - } - - public Builder callbackThreadMode(ThreadMode threadMode){ - mThreadMode = threadMode; - return this; - } - - public Builder userAgent(String ua){ - header("User-Agent", ua); - return this; - } - - public Builder contentType(@NonNull String contentType){ - this.mMediaType = MediaType.parse(contentType); - header("Content-Type", contentType); - return this; - } - - public Builder contentType(@NonNull MediaType mediaType){ - this.mMediaType = mediaType; - header("Content-Type", this.mMediaType.toString()); - return this; - } - - public Request build() { - if (mMediaType == null){ - // judgment request header - List headers = mRawBuilder.build().headers("Content-Type"); - final int len = headers.size(); - if (len != 0){ - StringBuilder mediaType = new StringBuilder(); - for (int i = 0; i < len; i++){ - mediaType.append(headers.get(i)); - } - mMediaType = MediaType.parse(mediaType.toString()); - if (mMediaType == null){ - mMediaType = MediaTypeUtils.DEFAULT; - } - } - // default is application/x-www-form-urlencoded - else { - mMediaType = MediaTypeUtils.DEFAULT; - } - } - - if (!Accept.EMPTY.equals(mCallback.accept())) { - addHeader("Accept", mCallback.accept()); - } - - switch (mMethod) { - case Method.GET: - mRawBuilder.method(mMethod, null); - mRawRequest = mRawBuilder.build(); - mRawRequest = mRawBuilder.url(mRequestParams.formatURLParams(mRawRequest.url())).build(); - break; - case Method.HEAD: - mRawBuilder.method(mMethod, null); - mRawRequest = mRawBuilder.build(); - break; - default: - if (MediaTypeUtils.isJSON(mMediaType) && mJsonBody != null) { - mRawBuilder.method(mMethod, new JSONBody(mJsonBody.toString())); - } - else if (mTextBody != null) { - mRawBuilder.method(mMethod, new RequestBody() { - @Override - public MediaType contentType() { - return mMediaType; - } - - @Override - public void writeTo(BufferedSink sink) throws IOException { - sink.write(mTextBody.getBytes(), 0, mTextBody.getBytes().length); - } - - @Override - public long contentLength() throws IOException { - return mTextBody.getBytes().length; - } - }); - } - else { - // inject callback if exist. - mRawBuilder.method(mMethod, mRequestParams.requestBody(mMediaType, - (mCallback instanceof AbsCallbackHandler ? (AbsCallbackHandler) mCallback : null))); - } - mRawRequest = mRawBuilder.build(); - break; - } - - return new Request(this); - } - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/RequestParams.java b/mhttp/src/main/java/im/wangchao/mhttp/RequestParams.java deleted file mode 100644 index 822338ac..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/RequestParams.java +++ /dev/null @@ -1,378 +0,0 @@ -package im.wangchao.mhttp; - -import androidx.annotation.NonNull; -import android.text.TextUtils; -import android.util.Pair; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import im.wangchao.mhttp.body.FileBody; -import im.wangchao.mhttp.body.JSONBody; -import im.wangchao.mhttp.body.MediaTypeUtils; -import im.wangchao.mhttp.body.OctetStreamBody; -import im.wangchao.mhttp.body.ProgressRequestBody; -import okhttp3.FormBody; -import okhttp3.HttpUrl; -import okhttp3.MediaType; -import okhttp3.MultipartBody; -import okhttp3.RequestBody; - -import static im.wangchao.mhttp.body.MediaTypeUtils.APPLICATION_OCTET_STREAM; - -/** - *

Description : RequestParams.

- *

Author : wangchao.

- *

Date : 15/8/17.

- *

Time : 下午2:16.

- */ -public class RequestParams{ - final private static String UTF_8_STR = "utf-8"; - final private static Charset UTF_8 = Charset.forName(UTF_8_STR); - - //params - final private List> urlParams = new ArrayList<>(); - final private ConcurrentHashMap streamParams = new ConcurrentHashMap<>(); - final private ConcurrentHashMap fileParams = new ConcurrentHashMap<>(); - - //default - private String contentEncoding = UTF_8_STR; - - public RequestParams(){ - this((Map)null); - } - - public RequestParams(Map params){ - if (params != null){ - for(Map.Entry entry : params.entrySet()){ - put(entry.getKey(), entry.getValue()); - } - } - } - - public RequestParams(Object...keysAndValues){ - int len = keysAndValues.length; - if (len % 2 != 0){ - throw new IllegalArgumentException("Supplied arguments must be even."); - } - for (int i = 0; i < len; i += 2){ - String key = String.valueOf(keysAndValues[i]); - String val = String.valueOf(keysAndValues[i + 1]); - put(key, val); - } - } - - public RequestParams(RequestParams params){ - if (params == null){ - return; - } - this.urlParams.addAll(params.getUrlParams()); - this.streamParams.putAll(params.getStreamParams()); - this.fileParams.putAll(params.getFileParams()); - this.contentEncoding = params.contentEncoding(); - } - - RequestBody requestBody(MediaType mediaType, AbsCallbackHandler callback){ - if (isJSON(mediaType)){ - Charset charset = mediaType.charset(); - if (charset == null){ - charset = UTF_8; - } - return new JSONBody(parseJSON(), charset.name()); - } - - if (isForm(mediaType)){ - return formBody(); - } - - MultipartBody.Builder builder = new MultipartBody.Builder(); - builder.setType(MultipartBody.FORM); - //form - for (Pair entry: urlParams){ - builder.addFormDataPart(entry.first, String.valueOf(entry.second)); - } - //stream - for (Map.Entry streamEntry: streamParams.entrySet()){ - builder.addPart( - okhttp3.Headers.of("Content-Disposition", - String.format("form-data;name=\"%s\";filename=\"%s\"", streamEntry.getKey(), streamEntry.getValue().name), - "Content-Transfer-Encoding", "binary"), - uploadProgressRequestBody( - new OctetStreamBody(streamEntry.getValue().inputStream, streamEntry.getValue().contentType), - callback)); - } - //file - for (Map.Entry file: fileParams.entrySet()){ - builder.addPart(uploadProgressRequestBody( - new FileBody(file.getValue().file, file.getValue().contentType), - callback - )); - } - - return builder.build(); - } - - private ProgressRequestBody uploadProgressRequestBody(RequestBody requestBody, AbsCallbackHandler callback){ - return new ProgressRequestBody(requestBody, callback); - } - - private FormBody formBody(){ - FormBody.Builder builder = new FormBody.Builder(); - for (Pair entry: urlParams){ - builder.add(entry.first, String.valueOf(entry.second)); - } - return builder.build(); - } - - /** - * @return Request body media type is JSON. - */ - private boolean isJSON(MediaType mediaType){ - return MediaTypeUtils.isJSON(mediaType) && streamParams.size() == 0 - && fileParams.size() == 0; - } - - /** - * @return Request body media type is Form. - */ - private boolean isForm(MediaType mediaType){ - return MediaTypeUtils.isFORM(mediaType) && streamParams.size() == 0 - && fileParams.size() == 0; - } - - /** - * Request body encoding. - */ - public RequestParams contentEncoding(@NonNull String encoding) { - if (Charset.isSupported(encoding)){ - this.contentEncoding = encoding; - } - return this; - } - - public String contentEncoding(){ - return contentEncoding; - } - - public void put(Map params){ - if (params != null){ - for(Map.Entry entry : params.entrySet()){ - put(entry.getKey(), entry.getValue()); - } - } - } - - public void put(List> params){ - if (params != null){ - urlParams.addAll(params); - } - } - - public void put(String key, String value) { - if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) { - urlParams.add(new Pair<>(key, value)); - } - } - - public void put(String key, Object value) { - if (!TextUtils.isEmpty(key) && (value != null)) { - if (value instanceof File){ - try { - put(key, (File)value); - } catch (FileNotFoundException e) { - // Silent - } - } else { - urlParams.add(new Pair<>(key, value)); - } - } - } - - - - public void put(String key, InputStream stream){ - put(key, stream, null); - } - - public void put(String key, InputStream stream, String name){ - put(key, stream, name, null); - } - - public void put(String key, InputStream stream, String name, String contentType){ - if (!TextUtils.isEmpty(key) && stream != null){ - streamParams.put(key, StreamWrapper.newInstance(stream, name, contentType)); - } - } - - public void put(File file) throws FileNotFoundException { - put(file, null); - } - - public void put(File file, String contentType) throws FileNotFoundException { - put(RequestParams.class.getSimpleName(), file, contentType); - } - - public void put(String key, File file) throws FileNotFoundException { - put(key, file, null); - } - - public void put(String key, File file, String contentType) throws FileNotFoundException { - if (file == null || !file.exists()){ - throw new FileNotFoundException(); - } - if (!TextUtils.isEmpty(key)){ - fileParams.put(key, new FileWrapper(file, contentType)); - } - } - - public void remove(String key){ - Pair removing = null; - for (Pair entry: urlParams) { - if (entry.first.equals(key)) { - removing = entry; - } - } - urlParams.remove(removing); - streamParams.remove(key); - fileParams.remove(key); - } - - public boolean has(String key){ - for (Pair entry: urlParams) { - if (entry.first.equals(key)) { - return true; - } - } - return (streamParams.containsKey(key) || fileParams.containsKey(key)); - } - - public boolean isEmpty(){ - return urlParams.isEmpty() && streamParams.isEmpty() && fileParams.isEmpty(); - } - - private String parseJSON(){ - JSONObject json = new JSONObject(); - - String key; - Object value; - for (Pair entry: urlParams){ - key = entry.first; - value = entry.second; - - if (key.isEmpty() || value == null){ - continue; - } - - try { - json.put(key, value); - } catch (JSONException e) { - // Silent - } - } - - return json.toString(); - } - - public ConcurrentHashMap getStreamParams() { - return streamParams; - } - - public ConcurrentHashMap getFileParams() { - return fileParams; - } - - public List> getUrlParams() { - return urlParams; - } - - public HttpUrl formatURLParams(HttpUrl url) { - HttpUrl.Builder builder = url.newBuilder(); - if (urlParams.size() != 0) { - for (Pair entry : urlParams) { - try { - builder.addEncodedQueryParameter(URLEncoder.encode(entry.first, contentEncoding), - URLEncoder.encode(String.valueOf(entry.second), contentEncoding)); - } catch (UnsupportedEncodingException e) { - //Silent - } - } - } - return builder.build(); - } - - /** - * Format get params. - */ - public String formatURLParams() { - StringBuilder sb = new StringBuilder(); - if (urlParams.size() != 0) { - for (Pair entry : urlParams) { - String encode = ""; - try { - encode = URLEncoder.encode(String.valueOf(entry.second), contentEncoding); - } catch (UnsupportedEncodingException e) { - //Silent - } - sb.append(entry.first).append("=").append(encode); - sb.append("&"); - } - sb.deleteCharAt(sb.length() - 1); - } - - return sb.toString().replace(" ", "%20"); - } - - /** - * Url params convert to {@link List}. - */ - public List> getParamsList(){ - List> params = new LinkedList<>(); - - for (Pair entry : urlParams) { - params.add(new Pair<>(entry.first, entry.second)); - } - - return params; - } - - public static class FileWrapper { - public final File file; - public final String contentType; - - public FileWrapper(File file, String contentType) { - this.file = file; - this.contentType = contentType; - } - } - - public static class StreamWrapper { - public final InputStream inputStream; - public final String name; - public final String contentType; - - public StreamWrapper(InputStream inputStream, String name, String contentType) { - this.inputStream = inputStream; - this.name = name; - this.contentType = contentType; - } - - static StreamWrapper newInstance(InputStream inputStream, String name, String contentType) { - return new StreamWrapper( - inputStream, - name, - TextUtils.isEmpty(contentType) ? APPLICATION_OCTET_STREAM : contentType); - } - } -} \ No newline at end of file diff --git a/mhttp/src/main/java/im/wangchao/mhttp/Response.java b/mhttp/src/main/java/im/wangchao/mhttp/Response.java deleted file mode 100644 index 8d1e16d7..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/Response.java +++ /dev/null @@ -1,63 +0,0 @@ -package im.wangchao.mhttp; - -import okhttp3.Headers; -import okhttp3.Protocol; - -/** - *

Description : MResponse.

- *

Author : wangchao.

- *

Date : 16/6/3.

- *

Time : 下午3:03.

- */ -public final class Response { - public final static int IO_EXCEPTION_CODE = 1000; - - public static Response error(Request request, int code, String message){ - if (message == null){ - message = "unknown exception."; - } - return new Response(request, new okhttp3.Response.Builder() - .request(request.raw()) - .protocol(Protocol.HTTP_1_1) - .code(code) - .message(message) - .build()); - } - - public static Response newResponse(Request request, okhttp3.Response raw){ - return new Response(request, raw); - } - - private final Request request; - private final okhttp3.Response rawResponse; - public String parserErrorBody = null; - - private Response(Request request, okhttp3.Response rawResponse){ - this.request = request; - this.rawResponse = rawResponse; - } - - public Request request() { - return request; - } - - public okhttp3.Response raw() { - return rawResponse; - } - - /** HTTP status code. */ - public int code() { - return rawResponse.code(); - } - - /** HTTP status message or null if unknown. */ - public String message() { - return rawResponse.message(); - } - - /** HTTP headers. */ - public Headers headers() { - return rawResponse.headers(); - } - -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/ThreadMode.java b/mhttp/src/main/java/im/wangchao/mhttp/ThreadMode.java deleted file mode 100644 index 49a23195..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/ThreadMode.java +++ /dev/null @@ -1,43 +0,0 @@ -package im.wangchao.mhttp; - -import java.util.concurrent.Executor; - -import im.wangchao.mhttp.executor.BACKGROUND; -import im.wangchao.mhttp.executor.MAIN; -import im.wangchao.mhttp.executor.SENDING; - -/** - *

Description : ThreadMode.

- *

Author : wangchao.

- *

Date : 16/8/3.

- *

Time : 下午12:44.

- */ -public enum ThreadMode { - /** - * Callback will be called in the same thread, which is sending the request. - */ - SENDING{ - @Override public Executor executor() { - return new SENDING(); - } - }, - /** - * Callback will be called in Android's main thread (UI thread). - */ - MAIN{ - @Override public Executor executor() { - return new MAIN(); - } - }, - - /** - * Callback will be called in a background thread. That is, work on the request thread(okhttp thread). - */ - BACKGROUND{ - @Override public Executor executor() { - return new BACKGROUND(); - } - }; - - public abstract Executor executor(); -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/URLInterceptor.java b/mhttp/src/main/java/im/wangchao/mhttp/URLInterceptor.java deleted file mode 100644 index 739a24f2..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/URLInterceptor.java +++ /dev/null @@ -1,20 +0,0 @@ -package im.wangchao.mhttp; - -import java.net.URL; - -import okhttp3.HttpUrl; - -/** - *

Description : URLInterceptor.

- *

Author : wangchao.

- *

Date : 2018/1/15.

- *

Time : 上午11:01.

- */ -public interface URLInterceptor { - - String interceptor(String origin); - - HttpUrl interceptor(HttpUrl origin); - - URL interceptor(URL origin); -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/body/FileBody.java b/mhttp/src/main/java/im/wangchao/mhttp/body/FileBody.java deleted file mode 100644 index 051dce2c..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/body/FileBody.java +++ /dev/null @@ -1,53 +0,0 @@ -package im.wangchao.mhttp.body; - -import androidx.annotation.NonNull; -import android.text.TextUtils; - -import java.io.File; -import java.io.IOException; - -import okhttp3.MediaType; -import okhttp3.RequestBody; -import okhttp3.internal.Util; -import okio.BufferedSink; -import okio.Okio; -import okio.Source; - -/** - *

Description : FileBody.

- *

Author : wangchao.

- *

Date : 16/3/8.

- *

Time : 下午6:10.

- */ -public final class FileBody extends RequestBody{ - private final static MediaType CONTENT_TYPE = MediaTypeUtils.OCTET; - private final MediaType contentType; - private final File file; - - public FileBody(File file){ - this(file, null); - } - - public FileBody(File file, String contentType){ - this.file = file; - this.contentType = TextUtils.isEmpty(contentType) ? CONTENT_TYPE : MediaType.parse(contentType); - } - - @Override public MediaType contentType() { - return contentType; - } - - @Override public long contentLength() throws IOException { - return file.length(); - } - - @Override public void writeTo(@NonNull BufferedSink sink) throws IOException { - Source source = null; - try { - source = Okio.source(file); - sink.writeAll(source); - } finally { - Util.closeQuietly(source); - } - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/body/JSONBody.java b/mhttp/src/main/java/im/wangchao/mhttp/body/JSONBody.java deleted file mode 100644 index 8449625c..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/body/JSONBody.java +++ /dev/null @@ -1,50 +0,0 @@ -package im.wangchao.mhttp.body; - -import androidx.annotation.NonNull; -import android.text.TextUtils; - -import java.io.IOException; - -import okhttp3.MediaType; -import okhttp3.RequestBody; -import okio.BufferedSink; - -/** - *

Description : JSONBody.

- *

Author : wangchao.

- *

Date : 16/3/8.

- *

Time : 下午4:31.

- */ -public final class JSONBody extends RequestBody{ - private final static MediaType CONTENT_TYPE = MediaTypeUtils.JSON; - private final MediaType contentType; - private final byte[] bytes; - - public JSONBody(String content){ - this(content, null); - } - - public JSONBody(String content, String charset){ - if (TextUtils.isEmpty(content)){ - throw new NullPointerException("content == null"); - } - if (TextUtils.isEmpty(charset)){ - charset = "utf-8"; - } - this.contentType = TextUtils.isEmpty(charset) ? CONTENT_TYPE : MediaType.parse("application/json; charset=" + charset); - bytes = content.getBytes(contentType.charset()); - } - - @Override public MediaType contentType() { - return contentType; - } - - @Override public long contentLength() throws IOException { - return bytes.length; - } - - @Override public void writeTo(@NonNull BufferedSink sink) throws IOException { - sink.write(bytes, 0, bytes.length); - } - -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/body/MediaTypeUtils.java b/mhttp/src/main/java/im/wangchao/mhttp/body/MediaTypeUtils.java deleted file mode 100644 index ff665962..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/body/MediaTypeUtils.java +++ /dev/null @@ -1,53 +0,0 @@ -package im.wangchao.mhttp.body; - -import androidx.annotation.NonNull; -import android.text.TextUtils; - -import okhttp3.MediaType; - -/** - *

Description : MediaType.

- *

Author : wangchao.

- *

Date : 2017/6/23.

- *

Time : 下午2:15.

- */ -public final class MediaTypeUtils { - /** MediaType String */ - public static final String APPLICATION_OCTET_STREAM = "application/octet-stream"; - public static final String APPLICATION_JSON = "application/json; charset=utf-8"; - public static final String APPLICATION_FORM = "application/x-www-form-urlencoded"; - public static final String APPLICATION_XML = "application/xml"; - - /** MediaType */ - public static final MediaType JSON = MediaType.parse(APPLICATION_JSON); - public static final MediaType OCTET = MediaType.parse(APPLICATION_OCTET_STREAM); - public static final MediaType FORM = MediaType.parse(APPLICATION_FORM); - public static final MediaType XML = MediaType.parse(APPLICATION_XML); - public static final MediaType DEFAULT = FORM; - - /** - * 判断两个 MediaType 是否相等,只判断 type 和 subType。 - */ - public static boolean equals(@NonNull MediaType first, @NonNull MediaType second){ - String first_type_subType = first.type().concat(first.subtype()); - String second_type_subType = second.type().concat(second.subtype()); - - return TextUtils.equals(first_type_subType, second_type_subType); - } - - public static boolean isJSON(@NonNull MediaType mediaType){ - return equals(mediaType, JSON); - } - - public static boolean isOCTET(@NonNull MediaType mediaType){ - return equals(mediaType, OCTET); - } - - public static boolean isFORM(@NonNull MediaType mediaType){ - return equals(mediaType, FORM); - } - - public static boolean isXML(@NonNull MediaType mediaType){ - return equals(mediaType, XML); - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/body/OctetStreamBody.java b/mhttp/src/main/java/im/wangchao/mhttp/body/OctetStreamBody.java deleted file mode 100644 index faf1c113..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/body/OctetStreamBody.java +++ /dev/null @@ -1,88 +0,0 @@ -package im.wangchao.mhttp.body; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import android.text.TextUtils; - -import java.io.IOException; -import java.io.InputStream; - -import okhttp3.MediaType; -import okhttp3.RequestBody; -import okhttp3.internal.Util; -import okio.Buffer; -import okio.BufferedSink; -import okio.Okio; -import okio.Source; - -/** - *

Description : OctetStreamBody.

- *

Author : wangchao.

- *

Date : 16/3/8.

- *

Time : 下午4:31.

- */ -public final class OctetStreamBody extends RequestBody{ - private final static MediaType CONTENT_TYPE = MediaTypeUtils.OCTET; - private final MediaType contentType; - private final InputStream stream; - private long contentLength = -1L; - private Buffer buffer; - - public OctetStreamBody(InputStream stream){ - this(stream, null); - } - - public OctetStreamBody(InputStream stream, String contentType){ - this.stream = stream; - this.contentType = TextUtils.isEmpty(contentType) ? CONTENT_TYPE : MediaType.parse(contentType); - } - - @Override public MediaType contentType() { - return contentType; - } - - @Override public long contentLength() throws IOException { - long result = contentLength; - if (result != -1L) return result; - return contentLength = writeOrCountBytes(null, true); - } - - @Override public void writeTo(@NonNull BufferedSink sink) throws IOException { - contentLength = writeOrCountBytes(sink, false); - } - - private long writeOrCountBytes(@Nullable BufferedSink sink, boolean countBytes) throws IOException{ - long byteCount = 0L; - - if (countBytes) { - buffer = new Buffer(); - Source source = null; - try { - source = Okio.source(stream); - buffer.writeAll(source); - } finally { - Util.closeQuietly(source); - } - - byteCount = buffer.size(); - - return byteCount; - } else { - if (sink == null){ - return byteCount; - } - Source source = null; - try { - source = Okio.source(buffer == null ? stream : buffer.inputStream()); - return sink.writeAll(source); - } finally { - if (buffer != null){ - buffer.clear(); - } - Util.closeQuietly(source); - } - } - - } - -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/body/ProgressRequestBody.java b/mhttp/src/main/java/im/wangchao/mhttp/body/ProgressRequestBody.java deleted file mode 100644 index 2ea2b901..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/body/ProgressRequestBody.java +++ /dev/null @@ -1,70 +0,0 @@ -package im.wangchao.mhttp.body; - -import androidx.annotation.NonNull; - -import java.io.IOException; - -import im.wangchao.mhttp.AbsCallbackHandler; -import okhttp3.MediaType; -import okhttp3.RequestBody; -import okio.Buffer; -import okio.BufferedSink; -import okio.ForwardingSink; -import okio.Okio; -import okio.Sink; - -/** - *

Description : ProgressRequestBody.

- *

Author : wangchao.

- *

Date : 2018/1/30.

- *

Time : 下午8:25.

- */ -public class ProgressRequestBody extends RequestBody { - - private final RequestBody mRequestBody; - private final AbsCallbackHandler mCallback; - private BufferedSink mBufferedSink; - - public ProgressRequestBody(RequestBody requestBody, AbsCallbackHandler callback){ - this.mRequestBody = requestBody; - this.mCallback = callback; - } - - @Override public MediaType contentType() { - return mRequestBody.contentType(); - } - - @Override public long contentLength() throws IOException { - return mRequestBody.contentLength(); - } - - @Override public void writeTo(@NonNull BufferedSink sink) throws IOException { - if (mCallback == null){ - mRequestBody.writeTo(sink); - return; - } - if (mBufferedSink == null){ - mBufferedSink = Okio.buffer(forward(sink)); - } - - mRequestBody.writeTo(mBufferedSink); - mBufferedSink.flush(); - } - - private Sink forward(Sink sink){ - return new ForwardingSink(sink) { - private long bytesWritten = 0L; - private long contentLength = 0L; - - @Override public void write(@NonNull Buffer source, long byteCount) throws IOException { - super.write(source, byteCount); - if (contentLength == 0) { - contentLength = contentLength(); - } - bytesWritten += byteCount; - - mCallback.sendUploadProgressEvent((int) bytesWritten, (int) contentLength); - } - }; - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/callback/BinaryCallbackHandler.java b/mhttp/src/main/java/im/wangchao/mhttp/callback/BinaryCallbackHandler.java deleted file mode 100644 index 05b763b9..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/callback/BinaryCallbackHandler.java +++ /dev/null @@ -1,30 +0,0 @@ -package im.wangchao.mhttp.callback; - -import im.wangchao.mhttp.AbsCallbackHandler; -import im.wangchao.mhttp.Accept; -import im.wangchao.mhttp.Response; - -/** - *

Description : BinaryResponseHandler.

- *

Author : wangchao.

- *

Date : 15/10/18.

- *

Time : 下午2:49.

- */ -public class BinaryCallbackHandler extends AbsCallbackHandler { - - @Override public void onSuccess(byte[] data, Response response) { - - } - - @Override public void onFailure(Response response, Throwable throwable) { - - } - - @Override public byte[] backgroundParser(Response response) throws Exception { - return response.raw().body().bytes(); - } - - @Override public String accept() { - return Accept.ACCEPT_DATA; - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/callback/BitmapCallbackHandler.java b/mhttp/src/main/java/im/wangchao/mhttp/callback/BitmapCallbackHandler.java deleted file mode 100644 index 3193703f..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/callback/BitmapCallbackHandler.java +++ /dev/null @@ -1,27 +0,0 @@ -package im.wangchao.mhttp.callback; - -import android.graphics.Bitmap; - -import im.wangchao.mhttp.AbsCallbackHandler; -import im.wangchao.mhttp.Accept; -import im.wangchao.mhttp.Response; - -/** - *

Description : ImageResponseHandler.

- *

Author : wangchao.

- *

Date : 15/10/18.

- *

Time : 下午2:49.

- */ -public abstract class BitmapCallbackHandler extends AbsCallbackHandler { - @Override public void onSuccess(Bitmap bitmap, Response response) { - } - - @Override public void onFailure(Response response, Throwable throwable) { - - } - - @Override public String accept() { - return Accept.ACCEPT_IMAGE; - } - -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/callback/CustomCallbackHandler.java b/mhttp/src/main/java/im/wangchao/mhttp/callback/CustomCallbackHandler.java deleted file mode 100644 index 537cb735..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/callback/CustomCallbackHandler.java +++ /dev/null @@ -1,34 +0,0 @@ -package im.wangchao.mhttp.callback; - -import im.wangchao.mhttp.Response; -import im.wangchao.mhttp.internal.exception.ParserException; - -/** - *

Description : GSONResponseHandler.

- *

Author : wangchao.

- *

Date : 16/3/20.

- *

Time : 上午9:06.

- */ -public abstract class CustomCallbackHandler extends TextCallbackHandler { - - @Override final public void onSuccess(String data, Response response) { - if (data != null) { - onSuccess(parser(data)); - } - else { - onFailure(response, new ParserException()); - } - } - - @Override public void onFailure(Response response, Throwable throwable) { - - } - - /** parser Json to T */ - protected abstract T parser(String data); - - public void onSuccess(T t){ - - } - -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/callback/FileCallbackHandler.java b/mhttp/src/main/java/im/wangchao/mhttp/callback/FileCallbackHandler.java deleted file mode 100644 index 796ec1cf..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/callback/FileCallbackHandler.java +++ /dev/null @@ -1,103 +0,0 @@ -package im.wangchao.mhttp.callback; - -import android.content.Context; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URLDecoder; - -import im.wangchao.mhttp.AbsCallbackHandler; -import im.wangchao.mhttp.Accept; -import im.wangchao.mhttp.Response; -import okhttp3.internal.Util; - -/** - *

Description : FileResponseHandler.

- *

Author : wangchao.

- *

Date : 15/10/18.

- *

Time : 下午2:39.

- */ -public class FileCallbackHandler extends AbsCallbackHandler { - private File file; - final private static int BUFFER_SIZE = 4096; - - public FileCallbackHandler(Context context){ - this.file = getTempFile(context); - } - - public FileCallbackHandler(File file){ - this.file = file; - } - - protected File getFile(){ - return file; - } - - @Override public void onSuccess(File file, Response response){ - - } - - @Override public void onFailure(Response response, Throwable throwable) { - - } - - @Override public File backgroundParser(Response response) throws IOException{ - writeFile(response.raw(), file); - return file; - } - - @Override public String accept() { - return Accept.ACCEPT_FILE; - } - - private File getTempFile(Context context){ - try { - return File.createTempFile("temp", "_handled", context.getCacheDir()); - } catch (IOException e) { - return null; - } - } - - /** - * write file , send progress message - */ - protected void writeFile(okhttp3.Response response, File file) throws IOException { - if (file == null){ - throw new IllegalArgumentException("File == null"); - } - if (this.file.isDirectory()) { - String contentDisposition = response.header("content-disposition"); - if (contentDisposition != null) { - if (contentDisposition.contains("*=UTF-8")) { - contentDisposition = contentDisposition.replace("*=UTF-8''", "\"") + "\""; - contentDisposition = URLDecoder.decode(contentDisposition, "UTF-8"); - } - String filename = contentDisposition.substring(contentDisposition.indexOf("\"") + 1, contentDisposition.lastIndexOf("\"")); - this.file = new File(file, filename); - file = this.file; - } - } - InputStream instream = response.body().byteStream(); - long contentLength = response.body().contentLength(); - FileOutputStream buffer = new FileOutputStream(file); - if (instream != null) { - try { - byte[] tmp = new byte[BUFFER_SIZE]; - int l; - long count = 0; - while ((l = instream.read(tmp)) != -1 && !Thread.currentThread().isInterrupted()) { - count += l; - buffer.write(tmp, 0, l); - - sendProgressEvent(count, contentLength); - } - } finally { - Util.closeQuietly(instream); - buffer.flush(); - Util.closeQuietly(buffer); - } - } - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/callback/JsonArrayCallbackHandler.java b/mhttp/src/main/java/im/wangchao/mhttp/callback/JsonArrayCallbackHandler.java deleted file mode 100644 index c417e097..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/callback/JsonArrayCallbackHandler.java +++ /dev/null @@ -1,37 +0,0 @@ -package im.wangchao.mhttp.callback; - -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; - -import im.wangchao.mhttp.AbsCallbackHandler; -import im.wangchao.mhttp.Accept; -import im.wangchao.mhttp.Response; - -public class JsonArrayCallbackHandler extends AbsCallbackHandler { - - @Override public void onSuccess(JsonArray data, Response response) { - - } - - @Override public void onFailure(Response response, Throwable throwable) { - - } - - @Override public JsonArray backgroundParser(Response response) throws Exception { - try { - byte[] body = response.raw().body().bytes(); - String bodyString = byteArrayToString(body); - JsonArray object = new JsonParser().parse(bodyString).getAsJsonArray(); - return object; - } - catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - @Override public String accept() { - return Accept.ACCEPT_JSON; - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/callback/JsonCallbackHandler.java b/mhttp/src/main/java/im/wangchao/mhttp/callback/JsonCallbackHandler.java deleted file mode 100644 index 2c16e9eb..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/callback/JsonCallbackHandler.java +++ /dev/null @@ -1,48 +0,0 @@ -package im.wangchao.mhttp.callback; - -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; - -import im.wangchao.mhttp.AbsCallbackHandler; -import im.wangchao.mhttp.Accept; -import im.wangchao.mhttp.Response; - -/** - *

Description : JSONResponseHandler.

- *

Author : wangchao.

- *

Date : 15/10/18.

- *

Time : 下午2:25.

- */ -public class JsonCallbackHandler extends AbsCallbackHandler { - - @Override public void onSuccess(JsonObject data, Response response) { - - } - - @Override public void onFailure(Response response, Throwable throwable) { - - } - - @Override public JsonObject backgroundParser(Response response) throws Exception { - try { - byte[] body = response.raw().body().bytes(); - String bodyString = byteArrayToString(body); - try { - return new JsonParser().parse(bodyString).getAsJsonObject(); - } - catch (Exception e) { - e.printStackTrace(); - response.parserErrorBody = bodyString; - return null; - } - } - catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - @Override public String accept() { - return Accept.ACCEPT_JSON; - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/callback/TextCallbackHandler.java b/mhttp/src/main/java/im/wangchao/mhttp/callback/TextCallbackHandler.java deleted file mode 100644 index a7781c2e..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/callback/TextCallbackHandler.java +++ /dev/null @@ -1,27 +0,0 @@ -package im.wangchao.mhttp.callback; - -import im.wangchao.mhttp.AbsCallbackHandler; -import im.wangchao.mhttp.Accept; -import im.wangchao.mhttp.Response; - -/** - *

Description : TextResponseHandler.

- *

Author : wangchao.

- *

Date : 15/10/18.

- *

Time : 下午2:41.

- */ -public class TextCallbackHandler extends AbsCallbackHandler { - @Override public void onSuccess(String data, Response response) { - } - - @Override public void onFailure(Response response, Throwable throwable) { - } - - @Override public String backgroundParser(Response response) throws Exception { - return byteArrayToString(response.raw().body().bytes()); - } - - @Override public String accept() { - return Accept.ACCEPT_TEXT; - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/executor/BACKGROUND.java b/mhttp/src/main/java/im/wangchao/mhttp/executor/BACKGROUND.java deleted file mode 100644 index 20eecd41..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/executor/BACKGROUND.java +++ /dev/null @@ -1,17 +0,0 @@ -package im.wangchao.mhttp.executor; - -import androidx.annotation.NonNull; - -import java.util.concurrent.Executor; - -/** - *

Description : BACKGROUND.

- *

Author : wangchao.

- *

Date : 16/9/2.

- *

Time : 下午4:50.

- */ -public final class BACKGROUND implements Executor { - @Override public void execute(@NonNull Runnable command) { - command.run(); - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/executor/MAIN.java b/mhttp/src/main/java/im/wangchao/mhttp/executor/MAIN.java deleted file mode 100644 index 57785d2d..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/executor/MAIN.java +++ /dev/null @@ -1,21 +0,0 @@ -package im.wangchao.mhttp.executor; - -import android.os.Handler; -import android.os.Looper; -import androidx.annotation.NonNull; - -import java.util.concurrent.Executor; - -/** - *

Description : MainThread.

- *

Author : wangchao.

- *

Date : 16/9/2.

- *

Time : 下午4:45.

- */ -public final class MAIN implements Executor{ - private final Handler handler = new Handler(Looper.getMainLooper()); - - @Override public void execute(@NonNull Runnable command) { - handler.post(command); - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/executor/SENDING.java b/mhttp/src/main/java/im/wangchao/mhttp/executor/SENDING.java deleted file mode 100644 index 5960bf4e..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/executor/SENDING.java +++ /dev/null @@ -1,27 +0,0 @@ -package im.wangchao.mhttp.executor; - -import android.os.Handler; -import android.os.Looper; -import androidx.annotation.NonNull; - -import java.util.concurrent.Executor; - -/** - *

Description : SENDING.

- *

Author : wangchao.

- *

Date : 16/9/2.

- *

Time : 下午4:47.

- */ -public final class SENDING implements Executor { - private final Handler handler; - public SENDING(){ - if (Looper.myLooper() == null){ - throw new RuntimeException("The Looper of the current thread is null, please call Looper.prepare() on your thread."); - } - handler = new Handler(Looper.myLooper()); - } - - @Override public void execute(@NonNull Runnable command) { - handler.post(command); - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/Singleton.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/Singleton.java deleted file mode 100644 index 2a351d6f..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/internal/Singleton.java +++ /dev/null @@ -1,25 +0,0 @@ -package im.wangchao.mhttp.internal; - -/** - *

Description : Singleton.

- *

Author : wangchao.

- *

Date : 16/8/25.

- *

Time : 上午10:37.

- */ -public abstract class Singleton { - private T instance; - - protected abstract T create(); - - public T get(){ - if (instance == null){ - synchronized (this){ - if (instance == null){ - instance = create(); - } - } - } - - return instance; - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/Version.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/Version.java deleted file mode 100644 index 847fe87e..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/internal/Version.java +++ /dev/null @@ -1,21 +0,0 @@ -package im.wangchao.mhttp.internal; - -/** - *

Description : Version.

- *

Author : wangchao.

- *

Date : 16/8/24.

- *

Time : 下午2:47.

- */ -public class Version { - private Version(){ - throw new AssertionError(); - } - - public static String userAgent() { - return moduleName().concat("1.10.1"); - } - - public static String moduleName() { - return "mhttp"; - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/ClearableCookieJar.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/ClearableCookieJar.java deleted file mode 100644 index 61c6e2ae..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/ClearableCookieJar.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2016 Francisco José Montiel Navarro. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package im.wangchao.mhttp.internal.cookie; - -import okhttp3.CookieJar; - -public interface ClearableCookieJar extends CookieJar { - - void clear(); - void clearForDomain(String domain); -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/MemoryCookieJar.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/MemoryCookieJar.java deleted file mode 100644 index 34ff5235..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/MemoryCookieJar.java +++ /dev/null @@ -1,60 +0,0 @@ -package im.wangchao.mhttp.internal.cookie; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import im.wangchao.mhttp.internal.cookie.cache.CookieCache; -import okhttp3.Cookie; -import okhttp3.HttpUrl; - -/** - *

Description : MemeryCookieJar.

- *

Author : wangchao.

- *

Date : 16/3/18.

- *

Time : 下午2:20.

- */ -public class MemoryCookieJar implements ClearableCookieJar { - - private CookieCache cache; - - public MemoryCookieJar(CookieCache cache) { - this.cache = cache; - } - - @Override - synchronized public void saveFromResponse(HttpUrl url, List cookies) { - cache.addAll(cookies); - } - - @Override - synchronized public List loadForRequest(HttpUrl url) { - List validCookies = new ArrayList<>(); - - for (Iterator it = cache.iterator(); it.hasNext(); ) { - Cookie currentCookie = it.next(); - - if (isCookieExpired(currentCookie)) { - it.remove(); - - } else if (currentCookie.matches(url)) { - validCookies.add(currentCookie); - } - } - - - return validCookies; - } - - private static boolean isCookieExpired(Cookie cookie) { - return cookie.expiresAt() < System.currentTimeMillis(); - } - - synchronized public void clear() { - cache.clear(); - } - - synchronized public void clearForDomain(String domain) { - cache.clearForDomain(domain); - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/PersistentCookieJar.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/PersistentCookieJar.java deleted file mode 100644 index 3a6b5a8c..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/PersistentCookieJar.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2016 Francisco José Montiel Navarro. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package im.wangchao.mhttp.internal.cookie; - - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -import im.wangchao.mhttp.internal.cookie.cache.CookieCache; -import im.wangchao.mhttp.internal.cookie.persistence.CookiePersistor; -import okhttp3.Cookie; -import okhttp3.HttpUrl; - -public class PersistentCookieJar implements ClearableCookieJar { - - private CookieCache cache; - private CookiePersistor persistor; - - public PersistentCookieJar(CookieCache cache, CookiePersistor persistor) { - this.cache = cache; - this.persistor = persistor; - - this.cache.addAll(persistor.loadAll()); - } - - @Override - synchronized public void saveFromResponse(@Nullable HttpUrl url, List cookies) { - // cookies need to be reversed, in order to replace old cookies with these coming later - // (if there are duplicate cookies in the same response) - List reverseCookies = new ArrayList<>(cookies); - Collections.reverse(reverseCookies); - cache.addAll(reverseCookies); - persistor.saveAll(reverseCookies); - } - - @NonNull - @Override - synchronized public List loadForRequest(HttpUrl url) { - List removedCookies = new ArrayList<>(); - List validCookies = new ArrayList<>(); - - for (Iterator it = cache.iterator(); it.hasNext(); ) { - Cookie currentCookie = it.next(); - if (isCookieExpired(currentCookie)) { - removedCookies.add(currentCookie); - it.remove(); - - } else if (currentCookie.matches(url)) { - validCookies.add(currentCookie); - } - } - - persistor.removeAll(removedCookies); - - return validCookies; - } - - @NonNull - synchronized public List getForDomain(String domain) { - List removedCookies = new ArrayList<>(); - List validCookies = new ArrayList<>(); - - for (Iterator it = cache.iterator(); it.hasNext(); ) { - Cookie currentCookie = it.next(); - if (isCookieExpired(currentCookie)) { - removedCookies.add(currentCookie); - it.remove(); - - } else if (domain.equals(currentCookie.domain())) { - validCookies.add(currentCookie); - } - } - - persistor.removeAll(removedCookies); - - return validCookies; - } - - @Nullable - synchronized public String getCookie(String domain, String name) { - String cookieValue = null; - List removedCookies = new ArrayList<>(); - - for (Iterator it = cache.iterator(); it.hasNext(); ) { - Cookie currentCookie = it.next(); - if (isCookieExpired(currentCookie)) { - removedCookies.add(currentCookie); - it.remove(); - - } else if (domain.equals(currentCookie.domain()) && name.equals(currentCookie.name())) { - cookieValue = currentCookie.value(); - break; - } - } - - persistor.removeAll(removedCookies); - - return cookieValue; - } - - private static boolean isCookieExpired(Cookie cookie) { - return cookie.expiresAt() < System.currentTimeMillis(); - } - - synchronized public void clear() { - cache.clear(); - persistor.clear(); - } - - synchronized public void clearForDomain(String domain) { - cache.clearForDomain(domain); - persistor.clearForDomain(domain); - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/cache/CookieCache.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/cache/CookieCache.java deleted file mode 100644 index 5b1de024..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/cache/CookieCache.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2016 Francisco José Montiel Navarro. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package im.wangchao.mhttp.internal.cookie.cache; - -import java.util.Collection; - -import okhttp3.Cookie; - -public interface CookieCache extends Iterable { - - /** - * Add all the new cookies to the session, existing cookies will be overwritten. - * - * @param cookies - */ - void addAll(Collection cookies); - - /** - * Clear all the cookies from the session. - */ - void clear(); - - void clearForDomain(String domain); -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/cache/IdentifiableCookie.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/cache/IdentifiableCookie.java deleted file mode 100644 index e10d269b..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/cache/IdentifiableCookie.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2016 Francisco José Montiel Navarro. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package im.wangchao.mhttp.internal.cookie.cache; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import okhttp3.Cookie; - -/** - * This class decorates a Cookie to re-implements equals() and hashcode() methods in order to identify - * the cookie by the following attributes: name, domain, path, secure & hostOnly.

- * - * This new behaviour will be useful in determining when an already existing cookie in session must be overwritten. - */ -class IdentifiableCookie { - - private Cookie cookie; - - static List decorateAll(Collection cookies) { - List identifiableCookies = new ArrayList<>(cookies.size()); - for (Cookie cookie : cookies) { - identifiableCookies.add(new IdentifiableCookie(cookie)); - } - return identifiableCookies; - } - - IdentifiableCookie(Cookie cookie) { - this.cookie = cookie; - } - - Cookie getCookie() { - return cookie; - } - - @Override - public boolean equals(Object other) { - if (!(other instanceof IdentifiableCookie)) return false; - IdentifiableCookie that = (IdentifiableCookie) other; - return that.cookie.name().equals(this.cookie.name()) - && that.cookie.domain().equals(this.cookie.domain()) - && that.cookie.path().equals(this.cookie.path()) - && that.cookie.secure() == this.cookie.secure() - && that.cookie.hostOnly() == this.cookie.hostOnly(); - } - - @Override - public int hashCode() { - int hash = 17; - if (cookie == null) - return hash; - hash = 31 * hash + cookie.name().hashCode(); - hash = 31 * hash + cookie.domain().hashCode(); - hash = 31 * hash + cookie.path().hashCode(); - hash = 31 * hash + (cookie.secure() ? 0 : 1); - hash = 31 * hash + (cookie.hostOnly() ? 0 : 1); - return hash; - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/cache/SetCookieCache.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/cache/SetCookieCache.java deleted file mode 100644 index 136df502..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/cache/SetCookieCache.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2016 Francisco José Montiel Navarro. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package im.wangchao.mhttp.internal.cookie.cache; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import okhttp3.Cookie; - -public class SetCookieCache implements CookieCache { - - private Set cookies; - - public SetCookieCache() { - cookies = new HashSet<>(); - } - - @Override - public void addAll(Collection newCookies) { - updateCookies(IdentifiableCookie.decorateAll(newCookies)); - } - - /** - * All cookies will be added to the collection, already existing cookies will be overwritten by the new ones. - * - * @param cookies - */ - private void updateCookies(Collection cookies) { - this.cookies.removeAll(cookies); - this.cookies.addAll(cookies); - } - - @Override - public void clear() { - cookies.clear(); - } - - @Override - public void clearForDomain(String domain) { - Collection removeCookies = new ArrayList<>(); - for (IdentifiableCookie cookie: cookies) { - if (cookie.getCookie().domain().equals(domain)) { - removeCookies.add(cookie); - } - } - cookies.removeAll(removeCookies); - } - - @Override - public Iterator iterator() { - return new SetCookieCacheIterator(); - } - - private class SetCookieCacheIterator implements Iterator { - - private Iterator iterator; - - public SetCookieCacheIterator() { - iterator = cookies.iterator(); - } - - @Override - public boolean hasNext() { - return iterator.hasNext(); - } - - @Override - public Cookie next() { - return iterator.next().getCookie(); - } - - @Override - public void remove() { - iterator.remove(); - } - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/persistence/CookiePersistor.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/persistence/CookiePersistor.java deleted file mode 100644 index 1346c662..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/persistence/CookiePersistor.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2016 Francisco José Montiel Navarro. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package im.wangchao.mhttp.internal.cookie.persistence; - -import java.util.Collection; -import java.util.List; - -import okhttp3.Cookie; - -public interface CookiePersistor { - - List loadAll(); - - /** - * Persist all cookies, existing cookies will be overwritten. - * - * @param cookies cookies persist - */ - void saveAll(Collection cookies); - - /** - * Removes indicated cookies from persistence. - * - * @param cookies cookies to remove from persistence - */ - void removeAll(Collection cookies); - - /** - * Clear all cookies from persistence. - */ - void clear(); - - /** - * Clear all cookies from persistence for specified url. - * - * @param domain domain name - */ - void clearForDomain(String domain); - -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/persistence/SerializableCookie.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/persistence/SerializableCookie.java deleted file mode 100644 index bce2efe8..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/persistence/SerializableCookie.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (C) 2016 Francisco José Montiel Navarro. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package im.wangchao.mhttp.internal.cookie.persistence; - -import android.util.Log; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; - -import okhttp3.Cookie; - -public class SerializableCookie implements Serializable { - private static final String TAG = SerializableCookie.class - .getSimpleName(); - - private transient Cookie cookie; - - public String encode(Cookie cookie) { - this.cookie = cookie; - - ByteArrayOutputStream os = new ByteArrayOutputStream(); - try { - ObjectOutputStream outputStream = new ObjectOutputStream(os); - outputStream.writeObject(this); - } catch (IOException e) { - Log.d(TAG, "IOException in encodeCookie", e); - return null; - } - - return byteArrayToHexString(os.toByteArray()); - } - - /** - * Using some super basic byte array <-> hex conversions so we don't - * have to rely on any large Base64 libraries. Can be overridden if you - * like! - * - * @param bytes byte array to be converted - * @return string containing hex values - */ - private static String byteArrayToHexString(byte[] bytes) { - StringBuilder sb = new StringBuilder(bytes.length * 2); - for (byte element : bytes) { - int v = element & 0xff; - if (v < 16) { - sb.append('0'); - } - sb.append(Integer.toHexString(v)); - } - return sb.toString(); - } - - public Cookie decode(String encodedCookie) { - byte[] bytes = hexStringToByteArray(encodedCookie); - ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( - bytes); - Cookie cookie = null; - try { - ObjectInputStream objectInputStream = new ObjectInputStream( - byteArrayInputStream); - cookie = ((SerializableCookie) objectInputStream.readObject()).cookie; - } catch (IOException e) { - Log.d(TAG, "IOException in decodeCookie", e); - } catch (ClassNotFoundException e) { - Log.d(TAG, "ClassNotFoundException in decodeCookie", e); - } - return cookie; - } - - /** - * Converts hex values from strings to byte array - * - * @param hexString string of hex-encoded values - * @return decoded byte array - */ - private static byte[] hexStringToByteArray(String hexString) { - int len = hexString.length(); - byte[] data = new byte[len / 2]; - for (int i = 0; i < len; i += 2) { - data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character - .digit(hexString.charAt(i + 1), 16)); - } - return data; - } - - private static long NON_VALID_EXPIRES_AT = -1l; - - private void writeObject(ObjectOutputStream out) throws IOException { - out.writeObject(cookie.name()); - out.writeObject(cookie.value()); - out.writeLong(cookie.persistent() ? cookie.expiresAt() : NON_VALID_EXPIRES_AT); - out.writeObject(cookie.domain()); - out.writeObject(cookie.path()); - out.writeBoolean(cookie.secure()); - out.writeBoolean(cookie.httpOnly()); - out.writeBoolean(cookie.hostOnly()); - } - - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - Cookie.Builder builder = new Cookie.Builder(); - - builder.name((String) in.readObject()); - - builder.value((String) in.readObject()); - - long expiresAt = in.readLong(); - if (expiresAt != NON_VALID_EXPIRES_AT) { - builder.expiresAt(expiresAt); - } - - final String domain = (String) in.readObject(); - builder.domain(domain); - - builder.path((String) in.readObject()); - - if (in.readBoolean()) - builder.secure(); - - if (in.readBoolean()) - builder.httpOnly(); - - if (in.readBoolean()) - builder.hostOnlyDomain(domain); - - cookie = builder.build(); - } - -} \ No newline at end of file diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/persistence/SharedPrefsCookiePersistor.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/persistence/SharedPrefsCookiePersistor.java deleted file mode 100644 index b1f82a09..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/persistence/SharedPrefsCookiePersistor.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2016 Francisco José Montiel Navarro. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package im.wangchao.mhttp.internal.cookie.persistence; - -import android.content.Context; -import android.content.SharedPreferences; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import okhttp3.Cookie; - -public class SharedPrefsCookiePersistor implements CookiePersistor { - - private SharedPreferences sharedPreferences; - - public SharedPrefsCookiePersistor(Context context) { - final String SHARED_PREFERENCES_NAME = "cookies"; - - sharedPreferences = - context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); - } - - @Override - public List loadAll() { - List cookies = new ArrayList<>(); - - for (Map.Entry entry : sharedPreferences.getAll().entrySet()) { - String serializedCookie = (String) entry.getValue(); - Cookie cookie = new SerializableCookie().decode(serializedCookie); - cookies.add(cookie); - } - return cookies; - } - - @Override - public void saveAll(Collection cookies) { - SharedPreferences.Editor editor = sharedPreferences.edit(); - for (Cookie cookie : cookies) { - if (cookie.persistent()) { - editor.putString(createCookieKey(cookie), new SerializableCookie().encode(cookie)); - } - } - editor.apply(); - } - - @Override - public void removeAll(Collection cookies) { - SharedPreferences.Editor editor = sharedPreferences.edit(); - for (Cookie cookie : cookies) { - editor.remove(createCookieKey(cookie)); - } - editor.apply(); - } - - private static String createCookieKey(Cookie cookie) { - return (cookie.secure() ? "https" : "http") + "://" + cookie.domain() + cookie.path() + "|" + cookie.name(); - } - - @Override - public void clear() { - sharedPreferences.edit().clear().apply(); - } - - @Override - public void clearForDomain(String domain) { - List cookies = loadAll(); - SharedPreferences.Editor editor = sharedPreferences.edit(); - for (Cookie cookie : cookies) { - if (cookie.domain().equals(domain)) - editor.remove(createCookieKey(cookie)); - } - editor.apply(); - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/exception/ParserException.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/exception/ParserException.java deleted file mode 100644 index 2b12087a..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/internal/exception/ParserException.java +++ /dev/null @@ -1,17 +0,0 @@ -package im.wangchao.mhttp.internal.exception; - -/** - *

Description : ParserException.

- *

Author : wangchao.

- *

Date : 16/4/26.

- *

Time : 下午8:38.

- */ -public class ParserException extends Exception{ - public ParserException(){ - super("Response parse exception."); - } - - public ParserException(Throwable cause) { - super("Response parse exception.", cause); - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/exception/ResponseFailException.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/exception/ResponseFailException.java deleted file mode 100644 index bb985e37..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/internal/exception/ResponseFailException.java +++ /dev/null @@ -1,14 +0,0 @@ -package im.wangchao.mhttp.internal.exception; - -/** - *

Description : ResponseFailException.

- *

Author : wangchao.

- *

Date : 16/4/25.

- *

Time : 下午4:06.

- */ -public class ResponseFailException extends Exception{ - //Response Non Successful - public ResponseFailException(){ - super("Response failure exception."); - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/interceptor/HttpLoggingInterceptor.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/interceptor/HttpLoggingInterceptor.java deleted file mode 100644 index 0ba2658a..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/internal/interceptor/HttpLoggingInterceptor.java +++ /dev/null @@ -1,320 +0,0 @@ -package im.wangchao.mhttp.internal.interceptor; - -/* - * Copyright (C) 2015 Square, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import java.io.EOFException; -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.concurrent.TimeUnit; - -import okhttp3.Connection; -import okhttp3.Headers; -import okhttp3.Interceptor; -import okhttp3.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; -import okhttp3.internal.http.HttpHeaders; -import okhttp3.internal.platform.Platform; -import okio.Buffer; -import okio.BufferedSource; -import okio.GzipSource; - -import static okhttp3.internal.platform.Platform.INFO; - -/** - * An OkHttp interceptor which logs request and response information. Can be applied as an - * {@linkplain OkHttpClient#interceptors() application interceptor} or as a {@linkplain - * OkHttpClient#networkInterceptors() network interceptor}.

The format of the logs created by - * this class should not be considered stable and may change slightly between releases. If you need - * a stable logging format, use your own interceptor. - */ -public final class HttpLoggingInterceptor implements Interceptor { - private static final Charset UTF8 = Charset.forName("UTF-8"); - - public enum Level { - /** No logs. */ - NONE, - /** - * Logs request and response lines. - * - *

Example: - *

{@code
-         * --> POST /greeting http/1.1 (3-byte body)
-         *
-         * <-- 200 OK (22ms, 6-byte body)
-         * }
- */ - BASIC, - /** - * Logs request and response lines and their respective headers. - * - *

Example: - *

{@code
-         * --> POST /greeting http/1.1
-         * Host: example.com
-         * Content-Type: plain/text
-         * Content-Length: 3
-         * --> END POST
-         *
-         * <-- 200 OK (22ms)
-         * Content-Type: plain/text
-         * Content-Length: 6
-         * <-- END HTTP
-         * }
- */ - HEADERS, - /** - * Logs request and response lines and their respective headers and bodies (if present). - * - *

Example: - *

{@code
-         * --> POST /greeting http/1.1
-         * Host: example.com
-         * Content-Type: plain/text
-         * Content-Length: 3
-         *
-         * Hi?
-         * --> END POST
-         *
-         * <-- 200 OK (22ms)
-         * Content-Type: plain/text
-         * Content-Length: 6
-         *
-         * Hello!
-         * <-- END HTTP
-         * }
- */ - BODY - } - - public interface Logger { - void log(String message); - - /** A {@link Logger} defaults output appropriate for the current platform. */ - Logger DEFAULT = new Logger() { - @Override public void log(String message) { - Platform.get().log(INFO, message, null); - } - }; - } - - public HttpLoggingInterceptor() { - this(Logger.DEFAULT); - } - - public HttpLoggingInterceptor(Logger logger) { - this.logger = logger; - } - - private final Logger logger; - - private volatile Level level = Level.NONE; - - /** Change the level at which this interceptor logs. */ - public HttpLoggingInterceptor setLevel(Level level) { - if (level == null) throw new NullPointerException("level == null. Use Level.NONE instead."); - this.level = level; - return this; - } - - public Level getLevel() { - return level; - } - - @Override public Response intercept(Chain chain) throws IOException { - Level level = this.level; - - Request request = chain.request(); - if (level == Level.NONE) { - return chain.proceed(request); - } - - boolean logBody = level == Level.BODY; - boolean logHeaders = logBody || level == Level.HEADERS; - - RequestBody requestBody = request.body(); - boolean hasRequestBody = requestBody != null; - - Connection connection = chain.connection(); - String requestStartMessage = "--> " - + request.method() - + ' ' + request.url() - + (connection != null ? " " + connection.protocol() : ""); - if (!logHeaders && hasRequestBody) { - requestStartMessage += " (" + requestBody.contentLength() + "-byte body)"; - } - logger.log(requestStartMessage); - - if (logHeaders) { - if (hasRequestBody) { - // Request body headers are only present when installed as a network interceptor. Force - // them to be included (when available) so there values are known. - if (requestBody.contentType() != null) { - logger.log("Content-Type: " + requestBody.contentType()); - } - if (requestBody.contentLength() != -1) { - logger.log("Content-Length: " + requestBody.contentLength()); - } - } - - Headers headers = request.headers(); - for (int i = 0, count = headers.size(); i < count; i++) { - String name = headers.name(i); - // Skip headers from the request body as they are explicitly logged above. - if (!"Content-Type".equalsIgnoreCase(name) && !"Content-Length".equalsIgnoreCase(name)) { - logger.log(name + ": " + headers.value(i)); - } - } - - if (!logBody || !hasRequestBody) { - logger.log("--> END " + request.method()); - } else if (bodyHasUnknownEncoding(request.headers())) { - logger.log("--> END " + request.method() + " (encoded body omitted)"); - } else { - Buffer buffer = new Buffer(); - requestBody.writeTo(buffer); - - Charset charset = UTF8; - MediaType contentType = requestBody.contentType(); - if (contentType != null) { - charset = contentType.charset(UTF8); - } - - logger.log(""); - if (isPlaintext(buffer)) { - logger.log(buffer.readString(charset)); - logger.log("--> END " + request.method() - + " (" + requestBody.contentLength() + "-byte body)"); - } else { - logger.log("--> END " + request.method() + " (binary " - + requestBody.contentLength() + "-byte body omitted)"); - } - } - } - - long startNs = System.nanoTime(); - Response response; - try { - response = chain.proceed(request); - } catch (Exception e) { - logger.log("<-- HTTP FAILED: " + e); - throw e; - } - long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs); - - ResponseBody responseBody = response.body(); - long contentLength = responseBody.contentLength(); - String bodySize = contentLength != -1 ? contentLength + "-byte" : "unknown-length"; - logger.log("<-- " - + response.code() - + (response.message().isEmpty() ? "" : ' ' + response.message()) - + ' ' + response.request().url() - + " (" + tookMs + "ms" + (!logHeaders ? ", " + bodySize + " body" : "") + ')'); - - if (logHeaders) { - Headers headers = response.headers(); - for (int i = 0, count = headers.size(); i < count; i++) { - logger.log(headers.name(i) + ": " + headers.value(i)); - } - - if (!logBody || !HttpHeaders.hasBody(response)) { - logger.log("<-- END HTTP"); - } else if (bodyHasUnknownEncoding(response.headers())) { - logger.log("<-- END HTTP (encoded body omitted)"); - } else { - BufferedSource source = responseBody.source(); - source.request(Long.MAX_VALUE); // Buffer the entire body. - Buffer buffer = source.buffer(); - - Long gzippedLength = null; - if ("gzip".equalsIgnoreCase(headers.get("Content-Encoding"))) { - gzippedLength = buffer.size(); - GzipSource gzippedResponseBody = null; - try { - gzippedResponseBody = new GzipSource(buffer.clone()); - buffer = new Buffer(); - buffer.writeAll(gzippedResponseBody); - } finally { - if (gzippedResponseBody != null) { - gzippedResponseBody.close(); - } - } - } - - Charset charset = UTF8; - MediaType contentType = responseBody.contentType(); - if (contentType != null) { - charset = contentType.charset(UTF8); - } - - if (!isPlaintext(buffer)) { - logger.log(""); - logger.log("<-- END HTTP (binary " + buffer.size() + "-byte body omitted)"); - return response; - } - - if (contentLength != 0) { - logger.log(""); - logger.log(buffer.clone().readString(charset)); - } - - if (gzippedLength != null) { - logger.log("<-- END HTTP (" + buffer.size() + "-byte, " - + gzippedLength + "-gzipped-byte body)"); - } else { - logger.log("<-- END HTTP (" + buffer.size() + "-byte body)"); - } - } - } - - return response; - } - - /** - * Returns true if the body in question probably contains human readable text. Uses a small sample - * of code points to detect unicode control characters commonly used in binary file signatures. - */ - static boolean isPlaintext(Buffer buffer) { - try { - Buffer prefix = new Buffer(); - long byteCount = buffer.size() < 64 ? buffer.size() : 64; - buffer.copyTo(prefix, 0, byteCount); - for (int i = 0; i < 16; i++) { - if (prefix.exhausted()) { - break; - } - int codePoint = prefix.readUtf8CodePoint(); - if (Character.isISOControl(codePoint) && !Character.isWhitespace(codePoint)) { - return false; - } - } - return true; - } catch (EOFException e) { - return false; // Truncated UTF-8 sequence. - } - } - - private boolean bodyHasUnknownEncoding(Headers headers) { - String contentEncoding = headers.get("Content-Encoding"); - return contentEncoding != null - && !contentEncoding.equalsIgnoreCase("identity") - && !contentEncoding.equalsIgnoreCase("gzip"); - } -} \ No newline at end of file diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/interceptor/MBridgeInterceptor.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/interceptor/MBridgeInterceptor.java deleted file mode 100644 index cd354e97..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/internal/interceptor/MBridgeInterceptor.java +++ /dev/null @@ -1,36 +0,0 @@ -package im.wangchao.mhttp.internal.interceptor; - -import java.io.IOException; - -import im.wangchao.mhttp.internal.Singleton; -import im.wangchao.mhttp.internal.Version; -import okhttp3.Interceptor; -import okhttp3.Request; -import okhttp3.Response; - -/** - *

Description : MBridgeInterceptors.

- *

Author : wangchao.

- *

Date : 16/8/24.

- *

Time : 下午4:32.

- */ -public final class MBridgeInterceptor implements Interceptor { - private MBridgeInterceptor(){} - - public static Singleton instance = new Singleton() { - @Override protected MBridgeInterceptor create() { - return new MBridgeInterceptor(); - } - }; - - @Override public Response intercept(Chain chain) throws IOException { - Request request = chain.request(); - Request.Builder builder = request.newBuilder(); - - if (request.header("User-Agent") == null) { - builder.header("User-Agent", Version.userAgent()); - } - - return chain.proceed(builder.build()); - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/log/LoggerImpl.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/log/LoggerImpl.java deleted file mode 100644 index d54fe9ce..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/internal/log/LoggerImpl.java +++ /dev/null @@ -1,35 +0,0 @@ -package im.wangchao.mhttp.internal.log; - -import android.util.Log; - -import im.wangchao.mhttp.internal.Singleton; -import im.wangchao.mhttp.internal.Version; -import im.wangchao.mhttp.internal.interceptor.HttpLoggingInterceptor; - -/** - *

Description : Logger.

- *

Author : wangchao.

- *

Date : 2018/3/20.

- *

Time : 下午5:36.

- */ -public class LoggerImpl implements HttpLoggingInterceptor.Logger{ - private static final String TAG = Version.moduleName(); - private HttpLoggingInterceptor.Level mLevel; - - public static Singleton instance = new Singleton() { - @Override protected LoggerImpl create() { - return new LoggerImpl(); - } - }; - - public void setLevel(HttpLoggingInterceptor.Level level){ - mLevel = level; - } - - @Override public void log(String message) { - if (mLevel == HttpLoggingInterceptor.Level.NONE){ - return; - } - Log.e(TAG, message); - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/rxjava2/ResponseEnqueueObservable.java b/mhttp/src/main/java/im/wangchao/mhttp/rxjava2/ResponseEnqueueObservable.java deleted file mode 100644 index b61ab6d4..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/rxjava2/ResponseEnqueueObservable.java +++ /dev/null @@ -1,133 +0,0 @@ -package im.wangchao.mhttp.rxjava2; - -import im.wangchao.mhttp.AbsCallbackHandler; -import im.wangchao.mhttp.Request; -import im.wangchao.mhttp.Response; -import io.reactivex.Observable; -import io.reactivex.Observer; -import io.reactivex.disposables.Disposable; -import io.reactivex.exceptions.CompositeException; -import io.reactivex.exceptions.Exceptions; -import io.reactivex.plugins.RxJavaPlugins; - -/** - *

Description : ResponseEnqueueObservable.

- *

Author : wangchao.

- *

Date : 2018/3/19.

- *

Time : 下午4:45.

- */ -public class ResponseEnqueueObservable extends Observable { - private final RxRequest request; - - public ResponseEnqueueObservable(RxRequest request){ - this.request = request; - } - - @Override protected void subscribeActual(Observer observer) { - - AbsCallbackHandler callback = request.callback(); - EnqueueDisposable disposable = new EnqueueDisposable<>(observer, callback); - - observer.onSubscribe(disposable); - request.request().newBuilder().callback(disposable).build().enqueue(); - } - - private static final class EnqueueDisposable extends AbsCallbackHandler implements Disposable{ - private final AbsCallbackHandler originCallback; - private final Observer observer; - private volatile boolean disposed; - boolean terminated = false; - - EnqueueDisposable(Observer observer, AbsCallbackHandler callbackHandler){ - this.observer = observer; - this.originCallback = callbackHandler; - } - - @Override public void dispose() { - disposed = true; - Request request = getRequest(); - request.cancel(); - } - - @Override public boolean isDisposed() { - return disposed; - } - - - @Override public String charset() { - return originCallback.charset(); - } - - @Override public String accept() { - return originCallback.accept(); - } - - @Override public void onStart() { - originCallback.onStart(); - } - - @Override public void onUploadProgress(int bytesWritten, int bytesTotal) { - originCallback.onUploadProgress(bytesWritten, bytesTotal); - } - - @Override public void onProgress(long bytesWritten, long bytesTotal) { - originCallback.onProgress(bytesWritten, bytesTotal); - } - - @Override public void onFinish() { - originCallback.onFinish(); - } - - @Override public void onCancel() { - originCallback.onCancel(); - if (!disposed){ - dispose(); - } - } - - @Override public T apply(Response response) throws Exception { - return originCallback.apply(response); - } - - @Override public void onSuccess(T data, Response response) { - if (disposed) return; - - try { - originCallback.onSuccess(data, response); - - observer.onNext(data); - - if (!disposed) { - terminated = true; - observer.onComplete(); - } - } catch (Throwable t) { - if (terminated) { - RxJavaPlugins.onError(t); - } else if (!disposed) { - try { - observer.onError(t); - } catch (Throwable inner) { - Exceptions.throwIfFatal(inner); - RxJavaPlugins.onError(new CompositeException(t, inner)); - } - } - } - } - - @Override public void onFailure(Response response, Throwable throwable) { - try { - originCallback.onFailure(response, throwable); - - observer.onError(throwable); - } catch (Throwable inner) { - Exceptions.throwIfFatal(inner); - RxJavaPlugins.onError(new CompositeException(throwable, inner)); - } - } - - @Override public void onFinally(Response response) { - originCallback.onFinally(response); - } - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/rxjava2/ResponseExecuteObservable.java b/mhttp/src/main/java/im/wangchao/mhttp/rxjava2/ResponseExecuteObservable.java deleted file mode 100644 index e68dfd2b..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/rxjava2/ResponseExecuteObservable.java +++ /dev/null @@ -1,76 +0,0 @@ -package im.wangchao.mhttp.rxjava2; - -import im.wangchao.mhttp.Converter; -import im.wangchao.mhttp.Request; -import im.wangchao.mhttp.Response; -import io.reactivex.Observable; -import io.reactivex.Observer; -import io.reactivex.disposables.Disposable; -import io.reactivex.exceptions.CompositeException; -import io.reactivex.exceptions.Exceptions; -import io.reactivex.plugins.RxJavaPlugins; - -/** - *

Description : ResponseExecuteObservable.

- *

Author : wangchao.

- *

Date : 2018/3/19.

- *

Time : 下午4:46.

- */ -public class ResponseExecuteObservable extends Observable { - private final RxRequest request; - private final Converter converter; - - public ResponseExecuteObservable(RxRequest request, Converter converter){ - this.request = request; - this.converter = converter; - } - - @Override protected void subscribeActual(Observer observer) { - - ExecuteDisposable disposable = new ExecuteDisposable(request.request()); - observer.onSubscribe(disposable); - - boolean terminated = false; - try { - T response = converter.apply(request.request().execute()); - if (!disposable.isDisposed()) { - observer.onNext(response); - } - if (!disposable.isDisposed()) { - terminated = true; - observer.onComplete(); - } - } catch (Throwable t) { - Exceptions.throwIfFatal(t); - if (terminated) { - RxJavaPlugins.onError(t); - } else if (!disposable.isDisposed()) { - try { - observer.onError(t); - } catch (Throwable inner) { - Exceptions.throwIfFatal(inner); - RxJavaPlugins.onError(new CompositeException(t, inner)); - } - } - } - - } - - private static final class ExecuteDisposable implements Disposable { - private final Request request; - private volatile boolean disposed; - - ExecuteDisposable(Request request) { - this.request = request; - } - - @Override public void dispose() { - disposed = true; - request.cancel(); - } - - @Override public boolean isDisposed() { - return disposed; - } - } -} diff --git a/mhttp/src/main/java/im/wangchao/mhttp/rxjava2/RxRequest.java b/mhttp/src/main/java/im/wangchao/mhttp/rxjava2/RxRequest.java deleted file mode 100644 index ef648ea0..00000000 --- a/mhttp/src/main/java/im/wangchao/mhttp/rxjava2/RxRequest.java +++ /dev/null @@ -1,233 +0,0 @@ -package im.wangchao.mhttp.rxjava2; - -import androidx.annotation.NonNull; - -import java.io.File; -import java.io.InputStream; -import java.net.URL; -import java.util.concurrent.Executor; - -import im.wangchao.mhttp.AbsCallbackHandler; -import im.wangchao.mhttp.Converter; -import im.wangchao.mhttp.Method; -import im.wangchao.mhttp.Request; -import im.wangchao.mhttp.RequestParams; -import im.wangchao.mhttp.Response; -import im.wangchao.mhttp.ThreadMode; -import io.reactivex.Observable; -import okhttp3.CacheControl; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.MediaType; - -/** - *

Description : RxRequest.

- *

Author : wangchao.

- *

Date : 2018/3/26.

- *

Time : 下午5:40.

- */ -public class RxRequest { - public static RxRequest.Builder builder(){ - return new RxRequest.Builder<>(); - } - - private Request request; - private AbsCallbackHandler callback; - - private RxRequest(Builder builder){ - request = builder.request; - callback = builder.callback; - } - - public Request request(){ - return request; - } - - public AbsCallbackHandler callback(){ - return callback; - } - - public RxRequest.Builder newBuilder() { - return new Builder<>(this); - } - - public Observable execute(Converter converter){ - return new ResponseExecuteObservable<>(this, converter); - } - - public Observable enqueue(){ - return new ResponseEnqueueObservable<>(this); - } - - public static final class Builder { - - Request request; - Request.Builder requestBuilder; - AbsCallbackHandler callback; - - public Builder() { - requestBuilder = new Request.Builder(); - callback = new AbsCallbackHandler() { - @Override public void onSuccess(T data, Response response) { - - } - - @Override public void onFailure(Response response, Throwable throwable) { - - } - }; - } - - private Builder(RxRequest request) { - requestBuilder = request.request.newBuilder(); - callback = request.callback; - } - - public Builder url(HttpUrl url) { - requestBuilder.url(url); - return this; - } - - public Builder url(String url) { - requestBuilder.url(url); - return this; - } - - public Builder url(URL url) { - requestBuilder.url(url); - return this; - } - - public Builder header(String name, String value) { - requestBuilder.header(name, value); - return this; - } - - public Builder addHeader(String name, String value) { - requestBuilder.header(name, value); - return this; - } - - public Builder removeHeader(String name) { - requestBuilder.removeHeader(name); - return this; - } - - public Builder headers(Headers headers) { - requestBuilder.headers(headers); - return this; - } - - public Builder cacheControl(CacheControl cacheControl) { - requestBuilder.cacheControl(cacheControl); - return this; - } - - public Builder get() { - return method(Method.GET); - } - - public Builder head() { - return method(Method.HEAD); - } - - public Builder post() { - return method(Method.POST); - } - - public Builder delete() { - return method(Method.DELETE); - } - - public Builder put() { - return method(Method.PUT); - } - - public Builder patch() { - return method(Method.PATCH); - } - - /** - * Simple to add request parameter - */ - public Builder addParameter(String key, Object value){ - requestBuilder.addParameter(key, value); - return this; - } - - /** - * Simple to add request parameter - */ - public Builder addParameter(String key, InputStream stream, String name){ - requestBuilder.addParameter(key, stream, name); - return this; - } - - /** - * Simple to add request parameter - */ - public Builder addParameter(String key, InputStream stream, String name, String contentType){ - requestBuilder.addParameter(key, stream, name, contentType); - return this; - } - - /** - * Simple to add request parameter - */ - public Builder addParameter(String key, File file, String contentType) { - requestBuilder.addParameter(key, file, contentType); - return this; - } - - public Builder requestParams(RequestParams params) { - requestBuilder.requestParams(params); - return this; - } - - public Builder method(@NonNull String method) { - requestBuilder.method(method); - return this; - } - - public Builder tag(Object tag) { - requestBuilder.tag(tag); - return this; - } - - public Builder callback(@NonNull AbsCallbackHandler callback){ - this.callback = callback; - return this; - } - - public Builder callbackExecutor(Executor executor){ - requestBuilder.callbackExecutor(executor); - return this; - } - - public Builder callbackThreadMode(ThreadMode threadMode){ - requestBuilder.callbackThreadMode(threadMode); - return this; - } - - public Builder userAgent(String ua){ - requestBuilder.userAgent(ua); - return this; - } - - public Builder contentType(@NonNull String contentType){ - requestBuilder.contentType(contentType); - return this; - } - - public Builder contentType(@NonNull MediaType mediaType){ - requestBuilder.contentType(mediaType); - return this; - } - - public RxRequest build() { - request = requestBuilder.build(); - - return new RxRequest<>(this); - } - } -} diff --git a/settings.gradle b/settings.gradle index f2de53d8..b47390e3 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,7 +3,7 @@ include ':wear' include ':codegen' include ':annotation' rootProject.name='Szkolny.eu' -include ':app', ':agendacalendarview', ':mhttp', ':szkolny-font' +include ':app', ':agendacalendarview', ':szkolny-font' /* include ':Navigation' project(':Navigation').projectDir = new File(settingsDir, '../Navigation/navlib')*/ From d78dad509036b397b404805ca6c42b1e09526dd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 20 Mar 2021 23:41:59 +0100 Subject: [PATCH 008/113] [Gradle] Extract agendacalendarview dependency. --- agendacalendarview/.gitignore | 1 - agendacalendarview/build.gradle | 54 --- .../src/main/AndroidManifest.xml | 3 - .../AgendaCalendarView.java | 264 -------------- .../agendacalendarview/CalendarManager.java | 267 -------------- .../CalendarPickerController.java | 14 - .../agenda/AgendaAdapter.java | 105 ------ .../agenda/AgendaEventView.java | 38 -- .../agenda/AgendaHeaderView.java | 81 ---- .../agenda/AgendaListView.java | 54 --- .../agendacalendarview/agenda/AgendaView.java | 145 -------- .../calendar/CalendarView.java | 279 -------------- .../calendar/weekslist/WeekListView.java | 144 -------- .../calendar/weekslist/WeeksAdapter.java | 321 ---------------- .../models/BaseCalendarEvent.java | 345 ------------------ .../models/CalendarEvent.java | 63 ---- .../agendacalendarview/models/DayItem.java | 145 -------- .../agendacalendarview/models/IDayItem.java | 49 --- .../agendacalendarview/models/IWeekItem.java | 34 -- .../agendacalendarview/models/WeekItem.java | 110 ------ .../render/DefaultEventRenderer.java | 82 ----- .../render/EventRenderer.java | 23 -- .../agendacalendarview/utils/BusProvider.java | 36 -- .../agendacalendarview/utils/DateHelper.java | 135 ------- .../agendacalendarview/utils/Events.java | 43 --- .../utils/ListViewScrollTracker.java | 114 ------ .../widgets/FloatingActionButton.java | 110 ------ .../main/res/drawable/agenda_day_circle.xml | 9 - .../main/res/drawable/event_color_circle.xml | 5 - .../src/main/res/drawable/fab_arrow.xml | 7 - .../drawable/selected_day_color_circle.xml | 8 - .../src/main/res/drawable/shadow.xml | 8 - .../src/main/res/layout/list_item_week.xml | 48 --- .../src/main/res/layout/view_agenda.xml | 23 -- .../src/main/res/layout/view_agenda_event.xml | 53 --- .../main/res/layout/view_agenda_header.xml | 64 ---- .../main/res/layout/view_agendacalendar.xml | 24 -- .../src/main/res/layout/view_calendar.xml | 48 --- .../res/layout/view_day_calendar_header.xml | 9 - .../src/main/res/layout/view_day_cell.xml | 85 ----- .../src/main/res/values-en/strings.xml | 12 - .../src/main/res/values/attrs.xml | 13 - .../src/main/res/values/colors.xml | 21 -- .../src/main/res/values/dimens.xml | 19 - .../src/main/res/values/strings.xml | 14 - .../src/main/res/values/styles.xml | 25 -- app/build.gradle | 4 +- settings.gradle | 2 +- 48 files changed, 2 insertions(+), 3558 deletions(-) delete mode 100644 agendacalendarview/.gitignore delete mode 100644 agendacalendarview/build.gradle delete mode 100644 agendacalendarview/src/main/AndroidManifest.xml delete mode 100644 agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/AgendaCalendarView.java delete mode 100644 agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/CalendarManager.java delete mode 100644 agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/CalendarPickerController.java delete mode 100644 agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaAdapter.java delete mode 100644 agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaEventView.java delete mode 100644 agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaHeaderView.java delete mode 100644 agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaListView.java delete mode 100644 agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaView.java delete mode 100644 agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/CalendarView.java delete mode 100644 agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/weekslist/WeekListView.java delete mode 100644 agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/weekslist/WeeksAdapter.java delete mode 100644 agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/BaseCalendarEvent.java delete mode 100644 agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/CalendarEvent.java delete mode 100644 agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/DayItem.java delete mode 100644 agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/IDayItem.java delete mode 100644 agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/IWeekItem.java delete mode 100644 agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/WeekItem.java delete mode 100644 agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/render/DefaultEventRenderer.java delete mode 100644 agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/render/EventRenderer.java delete mode 100644 agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/BusProvider.java delete mode 100644 agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/DateHelper.java delete mode 100644 agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/Events.java delete mode 100644 agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/ListViewScrollTracker.java delete mode 100644 agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/widgets/FloatingActionButton.java delete mode 100644 agendacalendarview/src/main/res/drawable/agenda_day_circle.xml delete mode 100644 agendacalendarview/src/main/res/drawable/event_color_circle.xml delete mode 100644 agendacalendarview/src/main/res/drawable/fab_arrow.xml delete mode 100644 agendacalendarview/src/main/res/drawable/selected_day_color_circle.xml delete mode 100644 agendacalendarview/src/main/res/drawable/shadow.xml delete mode 100644 agendacalendarview/src/main/res/layout/list_item_week.xml delete mode 100644 agendacalendarview/src/main/res/layout/view_agenda.xml delete mode 100644 agendacalendarview/src/main/res/layout/view_agenda_event.xml delete mode 100644 agendacalendarview/src/main/res/layout/view_agenda_header.xml delete mode 100644 agendacalendarview/src/main/res/layout/view_agendacalendar.xml delete mode 100644 agendacalendarview/src/main/res/layout/view_calendar.xml delete mode 100644 agendacalendarview/src/main/res/layout/view_day_calendar_header.xml delete mode 100644 agendacalendarview/src/main/res/layout/view_day_cell.xml delete mode 100644 agendacalendarview/src/main/res/values-en/strings.xml delete mode 100644 agendacalendarview/src/main/res/values/attrs.xml delete mode 100644 agendacalendarview/src/main/res/values/colors.xml delete mode 100644 agendacalendarview/src/main/res/values/dimens.xml delete mode 100644 agendacalendarview/src/main/res/values/strings.xml delete mode 100644 agendacalendarview/src/main/res/values/styles.xml diff --git a/agendacalendarview/.gitignore b/agendacalendarview/.gitignore deleted file mode 100644 index 796b96d1..00000000 --- a/agendacalendarview/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/agendacalendarview/build.gradle b/agendacalendarview/build.gradle deleted file mode 100644 index 92731fb9..00000000 --- a/agendacalendarview/build.gradle +++ /dev/null @@ -1,54 +0,0 @@ -apply plugin: 'com.android.library' -//apply plugin: 'me.tatarka.retrolambda' - -android { - compileSdkVersion setup.compileSdk - - android { - lintOptions { - abortOnError false - } - } - - defaultConfig { - minSdkVersion 14 - targetSdkVersion setup.targetSdk - versionCode 1 - versionName "1.0" - } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - debugMinify { - debuggable = true - minifyEnabled = true - proguardFiles 'proguard-android.txt' - } - } - sourceSets { - main { - assets.srcDirs = ['assets'] - } - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } -} - -//apply from: 'https://raw.github.com/chrisbanes/gradle-mvn-push/master/gradle-mvn-push.gradle' - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - // Google libraries - implementation "androidx.appcompat:appcompat:${versions.appcompat}" - implementation "androidx.recyclerview:recyclerview:${versions.recyclerView}" - implementation "com.google.android.material:material:${versions.material}" - - // other libraries - //implementation 'se.emilsjolander:stickylistheaders:2.7.0' - implementation 'com.github.edisonw:StickyListHeaders:master-SNAPSHOT@aar' - implementation 'io.reactivex:rxjava:1.1.1' -} diff --git a/agendacalendarview/src/main/AndroidManifest.xml b/agendacalendarview/src/main/AndroidManifest.xml deleted file mode 100644 index 38e54711..00000000 --- a/agendacalendarview/src/main/AndroidManifest.xml +++ /dev/null @@ -1,3 +0,0 @@ - - diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/AgendaCalendarView.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/AgendaCalendarView.java deleted file mode 100644 index 0d0c0cf4..00000000 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/AgendaCalendarView.java +++ /dev/null @@ -1,264 +0,0 @@ -package com.github.tibolte.agendacalendarview; - -import android.animation.Animator; -import android.animation.ObjectAnimator; -import android.content.Context; -import android.content.res.ColorStateList; -import android.content.res.TypedArray; -import android.os.Handler; -import androidx.annotation.NonNull; -import android.util.AttributeSet; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.AbsListView; -import android.widget.AdapterView; -import android.widget.FrameLayout; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.github.tibolte.agendacalendarview.agenda.AgendaAdapter; -import com.github.tibolte.agendacalendarview.agenda.AgendaView; -import com.github.tibolte.agendacalendarview.calendar.CalendarView; -import com.github.tibolte.agendacalendarview.models.BaseCalendarEvent; -import com.github.tibolte.agendacalendarview.models.CalendarEvent; -import com.github.tibolte.agendacalendarview.models.DayItem; -import com.github.tibolte.agendacalendarview.models.IDayItem; -import com.github.tibolte.agendacalendarview.models.IWeekItem; -import com.github.tibolte.agendacalendarview.models.WeekItem; -import com.github.tibolte.agendacalendarview.render.DefaultEventRenderer; -import com.github.tibolte.agendacalendarview.render.EventRenderer; -import com.github.tibolte.agendacalendarview.utils.BusProvider; -import com.github.tibolte.agendacalendarview.utils.Events; -import com.github.tibolte.agendacalendarview.utils.ListViewScrollTracker; -import com.github.tibolte.agendacalendarview.widgets.FloatingActionButton; - -import java.util.Calendar; -import java.util.List; -import java.util.Locale; - -import se.emilsjolander.stickylistheaders.StickyListHeadersListView; - -/** - * View holding the agenda and calendar view together. - */ -public class AgendaCalendarView extends FrameLayout implements StickyListHeadersListView.OnStickyHeaderChangedListener { - - private static final String LOG_TAG = AgendaCalendarView.class.getSimpleName(); - - private CalendarView mCalendarView; - private AgendaView mAgendaView; - private FloatingActionButton mFloatingActionButton; - - private int mAgendaCurrentDayTextColor, mCalendarHeaderColor, mCalendarHeaderTextColor, mCalendarBackgroundColor, mCalendarDayTextColor, mCalendarPastDayTextColor, mCalendarCurrentDayColor, mFabColor; - private CalendarPickerController mCalendarPickerController; - - public AgendaView getAgendaView() { - return mAgendaView; - } - - private ListViewScrollTracker mAgendaListViewScrollTracker; - private AbsListView.OnScrollListener mAgendaScrollListener = new AbsListView.OnScrollListener() { - int mCurrentAngle; - int mMaxAngle = 85; - - @Override - public void onScrollStateChanged(AbsListView view, int scrollState) { - - } - - @Override - public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { - int scrollY = mAgendaListViewScrollTracker.calculateScrollY(firstVisibleItem, visibleItemCount); - if (scrollY != 0) { - mFloatingActionButton.show(); - } - //Log.d(LOG_TAG, String.format("Agenda listView scrollY: %d", scrollY)); - /*int toAngle = scrollY / 100; - if (toAngle > mMaxAngle) { - toAngle = mMaxAngle; - } else if (toAngle < -mMaxAngle) { - toAngle = -mMaxAngle; - } - RotateAnimation rotate = new RotateAnimation(mCurrentAngle, toAngle, mFloatingActionButton.getWidth() / 2, mFloatingActionButton.getHeight() / 2); - rotate.setFillAfter(true); - mCurrentAngle = toAngle; - mFloatingActionButton.startAnimation(rotate);*/ - } - }; - - // region Constructors - - public AgendaCalendarView(Context context) { - super(context); - } - - public AgendaCalendarView(Context context, AttributeSet attrs) { - super(context, attrs); - - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ColorOptionsView, 0, 0); - mAgendaCurrentDayTextColor = a.getColor(R.styleable.ColorOptionsView_agendaCurrentDayTextColor, getResources().getColor(R.color.theme_primary)); - mCalendarHeaderColor = a.getColor(R.styleable.ColorOptionsView_calendarHeaderColor, getResources().getColor(R.color.theme_primary_dark)); - mCalendarHeaderTextColor = a.getColor(R.styleable.ColorOptionsView_calendarHeaderTextColor, getResources().getColor(R.color.theme_text_icons)); - mCalendarBackgroundColor = a.getColor(R.styleable.ColorOptionsView_calendarColor, getResources().getColor(R.color.theme_primary)); - mCalendarDayTextColor = a.getColor(R.styleable.ColorOptionsView_calendarDayTextColor, getResources().getColor(R.color.theme_text_icons)); - mCalendarCurrentDayColor = a.getColor(R.styleable.ColorOptionsView_calendarCurrentDayTextColor, getResources().getColor(R.color.calendar_text_current_day)); - mCalendarPastDayTextColor = a.getColor(R.styleable.ColorOptionsView_calendarPastDayTextColor, getResources().getColor(R.color.theme_light_primary)); - mFabColor = a.getColor(R.styleable.ColorOptionsView_fabColor, getResources().getColor(R.color.theme_accent)); - - LayoutInflater inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - inflater.inflate(R.layout.view_agendacalendar, this, true); - - setAlpha(0f); - } - - // endregion - - // region Class - View - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - mCalendarView = (CalendarView) findViewById(R.id.calendar_view); - mAgendaView = (AgendaView) findViewById(R.id.agenda_view); - mFloatingActionButton = (FloatingActionButton) findViewById(R.id.floating_action_button); - ColorStateList csl = new ColorStateList(new int[][]{new int[0]}, new int[]{mFabColor}); - mFloatingActionButton.setBackgroundTintList(csl); - - LinearLayout mDayNamesHeader = mCalendarView.findViewById(R.id.cal_day_names); - mDayNamesHeader.setBackgroundColor(mCalendarHeaderColor); - for (int i = 0; i < mDayNamesHeader.getChildCount(); i++) { - TextView txtDay = (TextView) mDayNamesHeader.getChildAt(i); - txtDay.setTextColor(mCalendarHeaderTextColor); - } - mCalendarView.findViewById(R.id.list_week).setBackgroundColor(mCalendarBackgroundColor); - - mAgendaView.getAgendaListView().setOnItemClickListener((AdapterView parent, View view, int position, long id) -> { - mCalendarPickerController.onEventSelected(CalendarManager.getInstance().getEvents().get(position)); - }); - - BusProvider.getInstance().toObserverable() - .subscribe(event -> { - if (event instanceof Events.DayClickedEvent) { - if (mCalendarPickerController != null) - mCalendarPickerController.onDaySelected(((Events.DayClickedEvent) event).getDay()); - } else if (event instanceof Events.EventsFetched) { - ObjectAnimator alphaAnimation = ObjectAnimator.ofFloat(this, "alpha", getAlpha(), 1f).setDuration(500); - alphaAnimation.addListener(new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { - - } - - @Override - public void onAnimationEnd(Animator animation) { - long fabAnimationDelay = 500; - // Just after setting the alpha from this view to 1, we hide the fab. - // It will reappear as soon as the user is scrolling the Agenda view. - new Handler().postDelayed(() -> { - mFloatingActionButton.hide(); - mAgendaListViewScrollTracker = new ListViewScrollTracker(mAgendaView.getAgendaListView()); - mAgendaView.getAgendaListView().setOnScrollListener(mAgendaScrollListener); - mFloatingActionButton.setOnClickListener((v) -> { - mAgendaView.translateList(0); - mAgendaView.getAgendaListView().smoothScrollBy(0, 0); - //mAgendaView.getAgendaListView().getWrappedList().smoothScrollBy(0, 0); - mAgendaView.getAgendaListView().scrollToCurrentDate(CalendarManager.getInstance().getToday()); - new Handler().postDelayed(() -> mFloatingActionButton.hide(), fabAnimationDelay); - }); - }, fabAnimationDelay); - } - - @Override - public void onAnimationCancel(Animator animation) { - - } - - @Override - public void onAnimationRepeat(Animator animation) { - - } - }); - alphaAnimation.start(); - } - }); - } - - // endregion - - // region Interface - StickyListHeadersListView.OnStickyHeaderChangedListener - - @Override - public void onStickyHeaderChanged(StickyListHeadersListView stickyListHeadersListView, View header, int position, long headerId) { - //Log.d(LOG_TAG, String.format("onStickyHeaderChanged, position = %d, headerId = %d", position, headerId)); - - if (CalendarManager.getInstance().getEvents().size() > 0) { - CalendarEvent event = CalendarManager.getInstance().getEvents().get(position); - if (event != null) { - mCalendarView.scrollToDate(event); - mCalendarPickerController.onScrollToDate(event.getInstanceDay()); - } - } - } - - // endregion - - // region Public methods - - public void init(List eventList, Calendar minDate, Calendar maxDate, Locale locale, CalendarPickerController calendarPickerController, EventRenderer ... renderers) { - mCalendarPickerController = calendarPickerController; - - CalendarManager.getInstance(getContext()).buildCal(minDate, maxDate, locale, new DayItem(), new WeekItem()); - - // Feed our views with weeks list and events - mCalendarView.init(CalendarManager.getInstance(getContext()), mCalendarDayTextColor, mCalendarCurrentDayColor, mCalendarPastDayTextColor, eventList); - - // Load agenda events and scroll to current day - AgendaAdapter agendaAdapter = new AgendaAdapter(mAgendaCurrentDayTextColor); - mAgendaView.getAgendaListView().setAdapter(agendaAdapter); - mAgendaView.getAgendaListView().setOnStickyHeaderChangedListener(this); - - CalendarManager.getInstance().loadEvents(eventList, new BaseCalendarEvent()); - BusProvider.getInstance().send(new Events.EventsFetched()); - Log.d(LOG_TAG, "CalendarEventTask finished, event count "+eventList.size()); - - // add default event renderer - addEventRenderer(new DefaultEventRenderer()); - for (EventRenderer renderer: renderers) { - addEventRenderer(renderer); - } - } - - public void init(Locale locale, List lWeeks, List lDays, List lEvents, CalendarPickerController calendarPickerController) { - mCalendarPickerController = calendarPickerController; - - CalendarManager.getInstance(getContext()).loadCal(locale, lWeeks, lDays, lEvents); - - // Feed our views with weeks list and events - mCalendarView.init(CalendarManager.getInstance(getContext()), mCalendarDayTextColor, mCalendarCurrentDayColor, mCalendarPastDayTextColor, lEvents); - - // Load agenda events and scroll to current day - AgendaAdapter agendaAdapter = new AgendaAdapter(mAgendaCurrentDayTextColor); - mAgendaView.getAgendaListView().setAdapter(agendaAdapter); - mAgendaView.getAgendaListView().setOnStickyHeaderChangedListener(this); - - // notify that actually everything is loaded - BusProvider.getInstance().send(new Events.EventsFetched()); - Log.d(LOG_TAG, "CalendarEventTask finished"); - - // add default event renderer - addEventRenderer(new DefaultEventRenderer()); - } - - public void addEventRenderer(@NonNull final EventRenderer renderer) { - AgendaAdapter adapter = (AgendaAdapter) mAgendaView.getAgendaListView().getAdapter(); - adapter.addEventRenderer(renderer); - } - - public void enableFloatingIndicator(boolean enable) { - mFloatingActionButton.setVisibility(enable ? VISIBLE : GONE); - } - - // endregion -} diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/CalendarManager.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/CalendarManager.java deleted file mode 100644 index c661d32b..00000000 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/CalendarManager.java +++ /dev/null @@ -1,267 +0,0 @@ -package com.github.tibolte.agendacalendarview; - -import com.github.tibolte.agendacalendarview.models.CalendarEvent; -import com.github.tibolte.agendacalendarview.models.IDayItem; -import com.github.tibolte.agendacalendarview.models.IWeekItem; -import com.github.tibolte.agendacalendarview.utils.DateHelper; - -import android.content.Context; -import android.util.Log; - -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.List; -import java.util.Locale; - -/** - * This class manages information about the calendar. (Events, weather info...) - * Holds reference to the days list of the calendar. - * As the app is using several views, we want to keep everything in one place. - */ -public class CalendarManager { - - private static final String LOG_TAG = CalendarManager.class.getSimpleName(); - - private static CalendarManager mInstance; - - private Context mContext; - private Locale mLocale; - private Calendar mToday = Calendar.getInstance(); - private SimpleDateFormat mWeekdayFormatter; - private SimpleDateFormat mMonthHalfNameFormat; - - /// instances of classes provided from outside - private IDayItem mCleanDay; - private IWeekItem mCleanWeek; - - /** - * List of days used by the calendar - */ - private List mDays = new ArrayList<>(); - /** - * List of weeks used by the calendar - */ - private List mWeeks = new ArrayList<>(); - /** - * List of events instances - */ - private List mEvents = new ArrayList<>(); - - // region Constructors - - public CalendarManager(Context context) { - this.mContext = context; - } - - public static CalendarManager getInstance(Context context) { - if (mInstance == null) { - mInstance = new CalendarManager(context); - } - return mInstance; - } - - public static CalendarManager getInstance() { - return mInstance; - } - - // endregion - - // region Getters/Setters - - public Locale getLocale() { - return mLocale; - } - - public Context getContext() { - return mContext; - } - - public Calendar getToday() { - return mToday; - } - - public void setToday(Calendar today) { - this.mToday = today; - } - - public List getWeeks() { - return mWeeks; - } - - public List getEvents() { - return mEvents; - } - - public List getDays() { - return mDays; - } - - public SimpleDateFormat getWeekdayFormatter() { - return mWeekdayFormatter; - } - - public SimpleDateFormat getMonthHalfNameFormat() { - return mMonthHalfNameFormat; - } - - // endregion - - // region Public methods - - public void buildCal(Calendar minDate, Calendar maxDate, Locale locale, IDayItem cleanDay, IWeekItem cleanWeek) { - if (minDate == null || maxDate == null) { - throw new IllegalArgumentException( - "minDate and maxDate must be non-null."); - } - if (minDate.after(maxDate)) { - throw new IllegalArgumentException( - "minDate must be before maxDate."); - } - if (locale == null) { - throw new IllegalArgumentException("Locale is null."); - } - - setLocale(locale); - - mDays.clear(); - mWeeks.clear(); - mEvents.clear(); - - mCleanDay = cleanDay; - mCleanWeek = cleanWeek; - - Calendar mMinCal = Calendar.getInstance(mLocale); - Calendar mMaxCal = Calendar.getInstance(mLocale); - Calendar mWeekCounter = Calendar.getInstance(mLocale); - - mMinCal.setTime(minDate.getTime()); - mMaxCal.setTime(maxDate.getTime()); - - // maxDate is exclusive, here we bump back to the previous day, as maxDate if December 1st, 2020, - // we don't include that month in our list - mMaxCal.add(Calendar.MINUTE, -1); - - // Now iterate we iterate between mMinCal and mMaxCal so we build our list of weeks - mWeekCounter.setTime(mMinCal.getTime()); - int maxMonth = mMaxCal.get(Calendar.MONTH); - int maxYear = mMaxCal.get(Calendar.YEAR); - - int currentMonth = mWeekCounter.get(Calendar.MONTH); - int currentYear = mWeekCounter.get(Calendar.YEAR); - - // Loop through the weeks - while ((currentMonth <= maxMonth // Up to, including the month. - || currentYear < maxYear) // Up to the year. - && currentYear < maxYear + 1) { // But not > next yr. - - Date date = mWeekCounter.getTime(); - // Build our week list - int currentWeekOfYear = mWeekCounter.get(Calendar.WEEK_OF_YEAR); - - IWeekItem weekItem = cleanWeek.copy(); - weekItem.setWeekInYear(currentWeekOfYear); - weekItem.setYear(currentYear); - weekItem.setDate(date); - weekItem.setMonth(currentMonth); - weekItem.setLabel(mMonthHalfNameFormat.format(date)); - List dayItems = getDayCells(mWeekCounter); // gather days for the built week - weekItem.setDayItems(dayItems); - mWeeks.add(weekItem); - - //Log.d(LOG_TAG, String.format("Adding week: %s", weekItem)); - - mWeekCounter.add(Calendar.WEEK_OF_YEAR, 1); - - currentMonth = mWeekCounter.get(Calendar.MONTH); - currentYear = mWeekCounter.get(Calendar.YEAR); - } - } - - public void loadEvents(List eventList, CalendarEvent noEvent) { - - for (IWeekItem weekItem : getWeeks()) { - for (IDayItem dayItem : weekItem.getDayItems()) { - boolean isEventForDay = false; - boolean isShowBadgeForDay = false; - for (CalendarEvent event : eventList) { - if (DateHelper.isBetweenInclusive(dayItem.getDate(), event.getStartTime(), event.getEndTime())) { - CalendarEvent copy = event.copy(); - - if (copy.getShowBadge()) { - isShowBadgeForDay = true; - } - - Calendar dayInstance = Calendar.getInstance(); - dayInstance.setTime(dayItem.getDate()); - copy.setInstanceDay(dayInstance); - copy.setDayReference(dayItem); - copy.setWeekReference(weekItem); - // add instances in chronological order - getEvents().add(copy); - isEventForDay = true; - } - } - if (!isEventForDay) { - Calendar dayInstance = Calendar.getInstance(); - dayInstance.setTime(dayItem.getDate()); - CalendarEvent copy = noEvent.copy(); - - copy.setInstanceDay(dayInstance); - copy.setDayReference(dayItem); - copy.setWeekReference(weekItem); - copy.setLocation(""); - copy.setTitle(getContext().getResources().getString(R.string.agenda_event_no_events)); - copy.setPlaceholder(true); - getEvents().add(copy); - } - dayItem.setShowBadge(isShowBadgeForDay); - } - } - } - - public void loadCal (Locale locale, List lWeeks, List lDays, List lEvents) { - mWeeks = lWeeks; - mDays = lDays; - mEvents = lEvents; - setLocale(locale); - } - - // endregion - - // region Private methods - - private List getDayCells(Calendar startCal) { - Calendar cal = Calendar.getInstance(mLocale); - cal.setTime(startCal.getTime()); - List dayItems = new ArrayList<>(); - - int firstDayOfWeek = cal.get(Calendar.DAY_OF_WEEK); - int offset = cal.getFirstDayOfWeek() - firstDayOfWeek; - if (offset > 0) { - offset -= 7; - } - cal.add(Calendar.DATE, offset); - - //Log.d(LOG_TAG, String.format("Buiding row week starting at %s", cal.getTime())); - for (int c = 0; c < 7; c++) { - IDayItem dayItem = mCleanDay.copy(); - dayItem.buildDayItemFromCal(cal); - dayItems.add(dayItem); - cal.add(Calendar.DATE, 1); - } - - mDays.addAll(dayItems); - return dayItems; - } - - private void setLocale(Locale locale) { - this.mLocale = locale; - setToday(Calendar.getInstance(mLocale)); - mWeekdayFormatter = new SimpleDateFormat(getContext().getString(R.string.day_name_format), mLocale); - mMonthHalfNameFormat = new SimpleDateFormat(getContext().getString(R.string.month_half_name_format), locale); - } - - // endregion -} diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/CalendarPickerController.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/CalendarPickerController.java deleted file mode 100644 index a2a86dde..00000000 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/CalendarPickerController.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.github.tibolte.agendacalendarview; - -import com.github.tibolte.agendacalendarview.models.CalendarEvent; -import com.github.tibolte.agendacalendarview.models.IDayItem; - -import java.util.Calendar; - -public interface CalendarPickerController { - void onDaySelected(IDayItem dayItem); - - void onEventSelected(CalendarEvent event); - - void onScrollToDate(Calendar calendar); -} diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaAdapter.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaAdapter.java deleted file mode 100644 index 2e6c6d31..00000000 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaAdapter.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.github.tibolte.agendacalendarview.agenda; - -import com.github.tibolte.agendacalendarview.models.CalendarEvent; -import com.github.tibolte.agendacalendarview.render.DefaultEventRenderer; -import com.github.tibolte.agendacalendarview.render.EventRenderer; - -import androidx.annotation.NonNull; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseAdapter; - -import java.util.ArrayList; -import java.util.List; - -import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter; - -/** - * Adapter for the agenda, implements StickyListHeadersAdapter. - * Days as sections and CalendarEvents as list items. - */ -public class AgendaAdapter extends BaseAdapter implements StickyListHeadersAdapter { - - private List mEvents = new ArrayList<>(); - private List> mRenderers = new ArrayList<>(); - private int mCurrentDayColor; - - // region Constructor - - public AgendaAdapter(int currentDayTextColor) { - this.mCurrentDayColor = currentDayTextColor; - } - - // endregion - - // region Public methods - - public void updateEvents(List events) { - this.mEvents.clear(); - this.mEvents.addAll(events); - notifyDataSetChanged(); - } - - // endregion - - // region Interface - StickyListHeadersAdapter - - @Override - public View getHeaderView(int position, View convertView, ViewGroup parent) { - AgendaHeaderView agendaHeaderView = (AgendaHeaderView) convertView; - if (agendaHeaderView == null) { - agendaHeaderView = AgendaHeaderView.inflate(parent); - } - agendaHeaderView.setDay(getItem(position).getInstanceDay(), mCurrentDayColor, getItem(position).getDayReference().getShowBadge()); - return agendaHeaderView; - } - - @Override - public long getHeaderId(int position) { - return mEvents.get(position).getInstanceDay().getTimeInMillis(); - } - - // endregion - - // region Class - BaseAdapter - - @Override - public int getCount() { - return mEvents.size(); - } - - @Override - public CalendarEvent getItem(int position) { - return mEvents.get(position); - } - - @Override - public long getItemId(int position) { - return position; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - EventRenderer eventRenderer = new DefaultEventRenderer(); - final CalendarEvent event = getItem(position); - - // Search for the correct event renderer - for (EventRenderer renderer : mRenderers) { - if(event.getClass().isAssignableFrom(renderer.getRenderType())) { - eventRenderer = renderer; - break; - } - } - convertView = LayoutInflater.from(parent.getContext()) - .inflate(eventRenderer.getEventLayout(), parent, false); - eventRenderer.render(convertView, event); - return convertView; - } - - public void addEventRenderer(@NonNull final EventRenderer renderer) { - mRenderers.add(renderer); - } - - // endregion -} \ No newline at end of file diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaEventView.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaEventView.java deleted file mode 100644 index 198f65cd..00000000 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaEventView.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.github.tibolte.agendacalendarview.agenda; - -import com.github.tibolte.agendacalendarview.R; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.ViewGroup; -import android.widget.LinearLayout; - -/** - * List item view for the StickyHeaderListView of the agenda view - */ -public class AgendaEventView extends LinearLayout { - public static AgendaEventView inflate(ViewGroup parent) { - return (AgendaEventView) LayoutInflater.from(parent.getContext()).inflate(R.layout.view_agenda_event, parent, false); - } - - // region Constructors - - public AgendaEventView(Context context) { - this(context, null); - } - - public AgendaEventView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public AgendaEventView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - setPadding(getResources().getDimensionPixelSize(R.dimen.agenda_event_view_padding_left), - getResources().getDimensionPixelSize(R.dimen.agenda_event_view_padding_top), - getResources().getDimensionPixelSize(R.dimen.agenda_event_view_padding_right), - getResources().getDimensionPixelSize(R.dimen.agenda_event_view_padding_bottom)); - } - - // endregion -} \ No newline at end of file diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaHeaderView.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaHeaderView.java deleted file mode 100644 index 36b16ddb..00000000 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaHeaderView.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.github.tibolte.agendacalendarview.agenda; - -import com.github.tibolte.agendacalendarview.CalendarManager; -import com.github.tibolte.agendacalendarview.R; -import com.github.tibolte.agendacalendarview.utils.DateHelper; - -import android.content.Context; -import android.content.res.Resources; -import android.graphics.drawable.GradientDrawable; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.LinearLayout; -import android.widget.TextView; - -import java.text.SimpleDateFormat; -import java.util.Calendar; - -/** - * Header view for the StickyHeaderListView of the agenda view - */ -public class AgendaHeaderView extends LinearLayout { - - public static AgendaHeaderView inflate(ViewGroup parent) { - return (AgendaHeaderView) LayoutInflater.from(parent.getContext()).inflate(R.layout.view_agenda_header, parent, false); - } - - // region Constructors - - public AgendaHeaderView(Context context) { - super(context); - } - - public AgendaHeaderView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public AgendaHeaderView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - // endregion - - // region Public methods - - public void setDay(Calendar day, int currentDayTextColor, boolean showBadge) { - TextView txtDayOfMonth = (TextView) findViewById(R.id.view_agenda_day_of_month); - TextView txtDayOfWeek = (TextView) findViewById(R.id.view_agenda_day_of_week); - TextView txtDay = (TextView) findViewById(R.id.view_agenda_day_text); - View circleView = findViewById(R.id.view_day_circle_selected); - - Calendar today = CalendarManager.getInstance().getToday(); - - SimpleDateFormat dayWeekFormatter = new SimpleDateFormat(getContext().getString(R.string.day_name_format), CalendarManager.getInstance().getLocale()); - SimpleDateFormat dayWeekLongFormatter = new SimpleDateFormat("EEEE", CalendarManager.getInstance().getLocale()); - - txtDayOfMonth.setTextColor(getResources().getColor(R.color.calendar_text_default)); - txtDayOfWeek.setTextColor(getResources().getColor(R.color.calendar_text_default)); - - if (DateHelper.sameDate(day, today)) { - txtDayOfMonth.setTextColor(currentDayTextColor); - circleView.setVisibility(VISIBLE); - GradientDrawable drawable = (GradientDrawable) circleView.getBackground(); - drawable.setStroke((int) (2 * Resources.getSystem().getDisplayMetrics().density), currentDayTextColor); - } else if (showBadge) { - circleView.setVisibility(VISIBLE); - GradientDrawable drawable = (GradientDrawable) circleView.getBackground(); - drawable.setStroke((int) (2 * Resources.getSystem().getDisplayMetrics().density), 0xffff0000); - } - else { - circleView.setVisibility(INVISIBLE); - } - - txtDayOfMonth.setText(String.valueOf(day.get(Calendar.DAY_OF_MONTH))); - txtDayOfWeek.setText(dayWeekFormatter.format(day.getTime())); - //txtDay.setText(dayWeekLongFormatter.format(day.getTime())); - } - - // endregion -} diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaListView.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaListView.java deleted file mode 100644 index 235b04c6..00000000 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaListView.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.github.tibolte.agendacalendarview.agenda; - -import com.github.tibolte.agendacalendarview.CalendarManager; -import com.github.tibolte.agendacalendarview.models.CalendarEvent; -import com.github.tibolte.agendacalendarview.utils.DateHelper; - -import android.content.Context; -import android.util.AttributeSet; - -import java.util.Calendar; -import java.util.List; - -import se.emilsjolander.stickylistheaders.StickyListHeadersListView; - -/** - * StickyListHeadersListView to scroll chronologically through events. - */ -public class AgendaListView extends StickyListHeadersListView { - - // region Constructors - - public AgendaListView(Context context) { - super(context); - } - - public AgendaListView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public AgendaListView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - // endregion - - // region Public methods - - public void scrollToCurrentDate(Calendar today) { - List events = CalendarManager.getInstance().getEvents(); - - int toIndex = 0; - for (int i = 0; i < events.size(); i++) { - if (DateHelper.sameDate(today, events.get(i).getInstanceDay())) { - toIndex = i; - break; - } - } - - final int finalToIndex = toIndex; - post(()->setSelection(finalToIndex)); - } - - // endregion -} diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaView.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaView.java deleted file mode 100644 index 80b317da..00000000 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaView.java +++ /dev/null @@ -1,145 +0,0 @@ -package com.github.tibolte.agendacalendarview.agenda; - -import android.animation.Animator; -import android.animation.ObjectAnimator; -import android.content.Context; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewTreeObserver; -import android.widget.FrameLayout; - -import com.github.tibolte.agendacalendarview.CalendarManager; -import com.github.tibolte.agendacalendarview.R; -import com.github.tibolte.agendacalendarview.utils.BusProvider; -import com.github.tibolte.agendacalendarview.utils.Events; - -public class AgendaView extends FrameLayout { - - private AgendaListView mAgendaListView; - private View mShadowView; - - // region Constructors - - public AgendaView(Context context) { - super(context); - } - - public AgendaView(Context context, AttributeSet attrs) { - super(context, attrs); - - LayoutInflater inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - inflater.inflate(R.layout.view_agenda, this, true); - } - - // endregion - - // region Class - View - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - - mAgendaListView = (AgendaListView) findViewById(R.id.agenda_listview); - mShadowView = findViewById(R.id.view_shadow); - - BusProvider.getInstance().toObserverable() - .subscribe(event -> { - if (event instanceof Events.DayClickedEvent) { - Events.DayClickedEvent clickedEvent = (Events.DayClickedEvent) event; - getAgendaListView().scrollToCurrentDate(clickedEvent.getCalendar()); - } else if (event instanceof Events.CalendarScrolledEvent) { - int offset = (int) (3 * getResources().getDimension(R.dimen.day_cell_height)); - translateList(offset); - } else if (event instanceof Events.EventsFetched) { - if (getAgendaListView().getAdapter() != null) - ((AgendaAdapter) getAgendaListView().getAdapter()).updateEvents(CalendarManager.getInstance().getEvents()); - - getViewTreeObserver().addOnGlobalLayoutListener( - new ViewTreeObserver.OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - if (getWidth() != 0 && getHeight() != 0) { - // display only two visible rows on the calendar view - ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams(); - int height = getHeight(); - int margin = (int) (getContext().getResources().getDimension(R.dimen.calendar_header_height) + 2 * getContext().getResources().getDimension(R.dimen.day_cell_height)); - layoutParams.height = height; - layoutParams.setMargins(0, margin, 0, 0); - setLayoutParams(layoutParams); - - getAgendaListView().scrollToCurrentDate(CalendarManager.getInstance().getToday()); - - getViewTreeObserver().removeGlobalOnLayoutListener(this); - } - } - } - - ); - } else if (event instanceof Events.ForecastFetched) { - ((AgendaAdapter) getAgendaListView().getAdapter()).updateEvents(CalendarManager.getInstance().getEvents()); - } - }); - } - - @Override - public boolean dispatchTouchEvent(MotionEvent event) { - int eventaction = event.getAction(); - - switch (eventaction) { - case MotionEvent.ACTION_DOWN: - // if the user touches the listView, we put it back to the top - translateList(0); - break; - default: - break; - } - - return super.dispatchTouchEvent(event); - } - - // endregion - - // region Public methods - - public AgendaListView getAgendaListView() { - return mAgendaListView; - } - - public void translateList(int targetY) { - if (targetY != getTranslationY()) { - ObjectAnimator mover = ObjectAnimator.ofFloat(this, "translationY", targetY); - mover.setDuration(150); - mover.addListener(new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { - //mShadowView.setVisibility(GONE); - } - - @Override - public void onAnimationEnd(Animator animation) { - if (targetY == 0) { - BusProvider.getInstance().send(new Events.AgendaListViewTouchedEvent()); - } - //mShadowView.setVisibility(VISIBLE); - } - - @Override - public void onAnimationCancel(Animator animation) { - - } - - @Override - public void onAnimationRepeat(Animator animation) { - - } - }); - mover.start(); - } - } - - // endregion -} diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/CalendarView.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/CalendarView.java deleted file mode 100644 index 67d7490c..00000000 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/CalendarView.java +++ /dev/null @@ -1,279 +0,0 @@ -package com.github.tibolte.agendacalendarview.calendar; - -import com.github.tibolte.agendacalendarview.CalendarManager; -import com.github.tibolte.agendacalendarview.R; -import com.github.tibolte.agendacalendarview.calendar.weekslist.WeekListView; -import com.github.tibolte.agendacalendarview.calendar.weekslist.WeeksAdapter; -import com.github.tibolte.agendacalendarview.models.CalendarEvent; -import com.github.tibolte.agendacalendarview.models.IDayItem; -import com.github.tibolte.agendacalendarview.models.IWeekItem; -import com.github.tibolte.agendacalendarview.utils.BusProvider; -import com.github.tibolte.agendacalendarview.utils.DateHelper; -import com.github.tibolte.agendacalendarview.utils.Events; - -import android.content.Context; -import androidx.recyclerview.widget.LinearLayoutManager; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.ViewGroup; -import android.view.ViewTreeObserver; -import android.widget.LinearLayout; -import android.widget.TextView; - -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.List; -import java.util.Locale; - -/** - * The calendar view is a freely scrolling view that allows the user to browse between days of the - * year. - */ -public class CalendarView extends LinearLayout { - - private static final String LOG_TAG = CalendarView.class.getSimpleName(); - - /** - * Top of the calendar view layout, the week days list - */ - private LinearLayout mDayNamesHeader; - /** - * Part of the calendar view layout always visible, the weeks list - */ - private WeekListView mListViewWeeks; - /** - * The adapter for the weeks list - */ - private WeeksAdapter mWeeksAdapter; - /** - * The current highlighted day in blue - */ - private IDayItem mSelectedDay; - /** - * The current row displayed at top of the list - */ - private int mCurrentListPosition; - - // region Constructors - - public CalendarView(Context context) { - super(context); - } - - public CalendarView(Context context, AttributeSet attrs) { - super(context, attrs); - - LayoutInflater inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - inflater.inflate(R.layout.view_calendar, this, true); - - setOrientation(VERTICAL); - } - - // endregion - - public IDayItem getSelectedDay() { - return mSelectedDay; - } - - public void setSelectedDay(IDayItem mSelectedDay) { - this.mSelectedDay = mSelectedDay; - } - - public WeekListView getListViewWeeks() { - return mListViewWeeks; - } - - // region Class - View - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - - mDayNamesHeader = (LinearLayout) findViewById(R.id.cal_day_names); - mListViewWeeks = (WeekListView) findViewById(R.id.list_week); - mListViewWeeks.setLayoutManager(new LinearLayoutManager(getContext())); - mListViewWeeks.setHasFixedSize(true); - mListViewWeeks.setItemAnimator(null); - mListViewWeeks.setSnapEnabled(true); - - // display only two visible rows on the calendar view - getViewTreeObserver().addOnGlobalLayoutListener( - new ViewTreeObserver.OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - if (getWidth() != 0 && getHeight() != 0) { - collapseCalendarView(); - getViewTreeObserver().removeGlobalOnLayoutListener(this); - } - } - } - ); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - - BusProvider.getInstance().toObserverable() - .subscribe(event -> { - if (event instanceof Events.CalendarScrolledEvent) { - expandCalendarView(); - } else if (event instanceof Events.AgendaListViewTouchedEvent) { - collapseCalendarView(); - } else if (event instanceof Events.DayClickedEvent) { - Events.DayClickedEvent clickedEvent = (Events.DayClickedEvent) event; - updateSelectedDay(clickedEvent.getCalendar(), clickedEvent.getDay()); - } - }); - } - - // endregion - - // region Public methods - - public void init(CalendarManager calendarManager, int dayTextColor, int currentDayTextColor, int pastDayTextColor, List eventList) { - Calendar today = calendarManager.getToday(); - Locale locale = calendarManager.getLocale(); - SimpleDateFormat weekDayFormatter = calendarManager.getWeekdayFormatter(); - List weeks = calendarManager.getWeeks(); - - setUpHeader(today, weekDayFormatter, locale); - setUpAdapter(today, weeks, dayTextColor, currentDayTextColor, pastDayTextColor, eventList); - scrollToDate(today, weeks); - } - - /** - * Fired when the Agenda list view changes section. - * - * @param calendarEvent The event for the selected position in the agenda listview. - */ - public void scrollToDate(final CalendarEvent calendarEvent) { - mListViewWeeks.post(()->scrollToPosition(updateSelectedDay(calendarEvent.getInstanceDay(), calendarEvent.getDayReference()))); - } - - public void scrollToDate(Calendar today, List weeks) { - Integer currentWeekIndex = null; - - for (int c = 0; c < weeks.size(); c++) { - if (DateHelper.sameWeek(today, weeks.get(c))) { - currentWeekIndex = c; - break; - } - } - - if (currentWeekIndex != null) { - final Integer finalCurrentWeekIndex = currentWeekIndex; - mListViewWeeks.post(() -> scrollToPosition(finalCurrentWeekIndex)); - } - } - - public void setBackgroundColor(int color) { - mListViewWeeks.setBackgroundColor(color); - } - - // endregion - - // region Private methods - - private void scrollToPosition(int targetPosition) { - LinearLayoutManager layoutManager = ((LinearLayoutManager) mListViewWeeks.getLayoutManager()); - layoutManager.scrollToPosition(targetPosition); - } - - private void updateItemAtPosition(int position) { - WeeksAdapter weeksAdapter = (WeeksAdapter) mListViewWeeks.getAdapter(); - weeksAdapter.notifyItemChanged(position); - } - - /** - * Creates a new adapter if necessary and sets up its parameters. - */ - private void setUpAdapter(Calendar today, List weeks, int dayTextColor, int currentDayTextColor, int pastDayTextColor, List events) { - BusProvider.getInstance().toObserverable() - .subscribe(event -> { - if (event instanceof Events.EventsFetched) { - //Log.d("CalendarView", "events size "+events.size()); - if (mWeeksAdapter == null) { - //Log.d(LOG_TAG, "Setting adapter with today's calendar: " + today.toString()); - mWeeksAdapter = new WeeksAdapter(getContext(), today, dayTextColor, currentDayTextColor, pastDayTextColor, events); - mListViewWeeks.setAdapter(mWeeksAdapter); - } - mWeeksAdapter.updateWeeksItems(weeks); - }}); - - } - - private void setUpHeader(Calendar today, SimpleDateFormat weekDayFormatter, Locale locale) { - int daysPerWeek = 7; - String[] dayLabels = new String[daysPerWeek]; - Calendar cal = Calendar.getInstance(CalendarManager.getInstance(getContext()).getLocale()); - cal.setTime(today.getTime()); - int firstDayOfWeek = cal.getFirstDayOfWeek(); - for (int count = 0; count < 7; count++) { - cal.set(Calendar.DAY_OF_WEEK, firstDayOfWeek + count); - if (locale.getLanguage().equals("en")) { - dayLabels[count] = weekDayFormatter.format(cal.getTime()).toUpperCase(locale); - } else { - dayLabels[count] = weekDayFormatter.format(cal.getTime()); - } - } - - for (int i = 0; i < mDayNamesHeader.getChildCount(); i++) { - TextView txtDay = (TextView) mDayNamesHeader.getChildAt(i); - txtDay.setText(dayLabels[i]); - } - } - - private void expandCalendarView() { - ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams(); - layoutParams.height = (int) (getResources().getDimension(R.dimen.calendar_header_height) + 5 * getResources().getDimension(R.dimen.day_cell_height)); - setLayoutParams(layoutParams); - } - - private void collapseCalendarView() { - ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams(); - layoutParams.height = (int) (getResources().getDimension(R.dimen.calendar_header_height) + 2 * getResources().getDimension(R.dimen.day_cell_height)); - setLayoutParams(layoutParams); - } - - /** - * Update a selected cell day item. - * - * @param calendar The Calendar instance of the day selected. - * @param dayItem The DayItem information held by the cell item. - * @return The selected row of the weeks list, to be updated. - */ - private int updateSelectedDay(Calendar calendar, IDayItem dayItem) { - Integer currentWeekIndex = null; - - // update highlighted/selected day - if (!dayItem.equals(getSelectedDay())) { - dayItem.setSelected(true); - if (getSelectedDay() != null) { - getSelectedDay().setSelected(false); - } - setSelectedDay(dayItem); - } - - for (int c = 0; c < CalendarManager.getInstance().getWeeks().size(); c++) { - if (DateHelper.sameWeek(calendar, CalendarManager.getInstance().getWeeks().get(c))) { - currentWeekIndex = c; - break; - } - } - - if (currentWeekIndex != null) { - // highlighted day has changed, update the rows concerned - if (currentWeekIndex != mCurrentListPosition) { - updateItemAtPosition(mCurrentListPosition); - } - mCurrentListPosition = currentWeekIndex; - updateItemAtPosition(currentWeekIndex); - } - - return mCurrentListPosition; - } - - // endregion -} diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/weekslist/WeekListView.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/weekslist/WeekListView.java deleted file mode 100644 index 099bc6eb..00000000 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/weekslist/WeekListView.java +++ /dev/null @@ -1,144 +0,0 @@ -package com.github.tibolte.agendacalendarview.calendar.weekslist; - -import com.github.tibolte.agendacalendarview.utils.BusProvider; -import com.github.tibolte.agendacalendarview.utils.Events; - -import android.content.Context; -import androidx.recyclerview.widget.RecyclerView; -import android.util.AttributeSet; -import android.view.View; - -public class WeekListView extends RecyclerView { - private boolean mUserScrolling = false; - private boolean mScrolling = false; - - // region Constructors - - public WeekListView(Context context) { - super(context); - } - - public WeekListView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public WeekListView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - // endregion - - // region Public methods - - /** - * Enable snapping behaviour for this recyclerView - * - * @param enabled enable or disable the snapping behaviour - */ - public void setSnapEnabled(boolean enabled) { - if (enabled) { - addOnScrollListener(mScrollListener); - } else { - removeOnScrollListener(mScrollListener); - } - } - - // endregion - - // region Private methods - - private OnScrollListener mScrollListener = new OnScrollListener() { - @Override - public void onScrolled(RecyclerView recyclerView, int dx, int dy) { - super.onScrolled(recyclerView, dx, dy); - } - - @Override - public void onScrollStateChanged(RecyclerView recyclerView, int newState) { - super.onScrollStateChanged(recyclerView, newState); - final WeeksAdapter weeksAdapter = (WeeksAdapter) getAdapter(); - - switch (newState) { - case SCROLL_STATE_IDLE: - if (mUserScrolling) { - scrollToView(getCenterView()); - postDelayed(() -> weeksAdapter.setDragging(false), 700); // Wait for recyclerView to settle - } - - mUserScrolling = false; - mScrolling = false; - break; - // If scroll is caused by a touch (scroll touch, not any touch) - case SCROLL_STATE_DRAGGING: - BusProvider.getInstance().send(new Events.CalendarScrolledEvent()); - // If scroll was initiated already, this is not a user scrolling, but probably a tap, else set userScrolling - if (!mScrolling) { - mUserScrolling = true; - } - weeksAdapter.setDragging(true); - break; - case SCROLL_STATE_SETTLING: - // The user's finger is not touching the list anymore, no need - // for any alpha animation then - weeksAdapter.setAlphaSet(true); - mScrolling = true; - break; - } - } - }; - - private View getChildClosestToPosition(int y) { - if (getChildCount() <= 0) { - return null; - } - - int itemHeight = getChildAt(0).getMeasuredHeight(); - - int closestY = 9999; - View closestChild = null; - - for (int i = 0; i < getChildCount(); i++) { - View child = getChildAt(i); - - int childCenterY = ((int) child.getY() + (itemHeight / 2)); - int yDistance = childCenterY - y; - - // If child center is closer than previous closest, set it as closest - if (Math.abs(yDistance) < Math.abs(closestY)) { - closestY = yDistance; - closestChild = child; - } - } - - return closestChild; - } - - private View getCenterView() { - return getChildClosestToPosition(getMeasuredHeight() / 2); - } - - private void scrollToView(View child) { - if (child == null) { - return; - } - - stopScroll(); - - int scrollDistance = getScrollDistance(child); - - if (scrollDistance != 0) { - smoothScrollBy(0, scrollDistance); - } - } - - private int getScrollDistance(View child) { - int itemHeight = getChildAt(0).getMeasuredHeight(); - int centerY = getMeasuredHeight() / 2; - - int childCenterY = ((int) child.getY() + (itemHeight / 2)); - - return childCenterY - centerY; - } - - // endregion -} diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/weekslist/WeeksAdapter.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/weekslist/WeeksAdapter.java deleted file mode 100644 index df2177df..00000000 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/weekslist/WeeksAdapter.java +++ /dev/null @@ -1,321 +0,0 @@ -package com.github.tibolte.agendacalendarview.calendar.weekslist; - -import com.github.tibolte.agendacalendarview.CalendarManager; -import com.github.tibolte.agendacalendarview.R; -import com.github.tibolte.agendacalendarview.models.CalendarEvent; -import com.github.tibolte.agendacalendarview.models.IDayItem; -import com.github.tibolte.agendacalendarview.models.IWeekItem; -import com.github.tibolte.agendacalendarview.utils.BusProvider; -import com.github.tibolte.agendacalendarview.utils.DateHelper; -import com.github.tibolte.agendacalendarview.utils.Events; - -import android.animation.Animator; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; -import android.content.Context; -import android.content.res.Resources; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffColorFilter; -import android.graphics.Typeface; -import android.graphics.drawable.GradientDrawable; - -import androidx.recyclerview.widget.RecyclerView; - -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; -import android.widget.LinearLayout; -import android.widget.TextView; - -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.List; - -public class WeeksAdapter extends RecyclerView.Adapter { - - public static final long FADE_DURATION = 250; - - private Context mContext; - private Calendar mToday; - private List mWeeksList = new ArrayList<>(); - private List mEventList = new ArrayList<>(); - private boolean mDragging; - private boolean mAlphaSet; - private int mDayTextColor, mPastDayTextColor, mCurrentDayColor; - - // region Constructor - - public WeeksAdapter(Context context, Calendar today, int dayTextColor, int currentDayTextColor, int pastDayTextColor, List events) { - this.mToday = today; - this.mContext = context; - this.mDayTextColor = dayTextColor; - this.mCurrentDayColor = currentDayTextColor; - this.mPastDayTextColor = pastDayTextColor; - this.mEventList = events; - } - - // endregion - - public void updateWeeksItems(List weekItems) { - this.mWeeksList.clear(); - this.mWeeksList.addAll(weekItems); - notifyDataSetChanged(); - } - - // region Getters/setters - - public List getWeeksList() { - return mWeeksList; - } - - public boolean isDragging() { - return mDragging; - } - - public void setDragging(boolean dragging) { - if (dragging != this.mDragging) { - this.mDragging = dragging; - notifyItemRangeChanged(0, mWeeksList.size()); - } - } - - public boolean isAlphaSet() { - return mAlphaSet; - } - - public void setAlphaSet(boolean alphaSet) { - mAlphaSet = alphaSet; - } - - // endregion - - // region RecyclerView.Adapter methods - - @Override - public WeekViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_week, parent, false); - return new WeekViewHolder(view); - } - - @Override - public void onBindViewHolder(WeekViewHolder weekViewHolder, int position) { - IWeekItem weekItem = mWeeksList.get(position); - weekViewHolder.bindWeek(weekItem, mToday); - } - - @Override - public int getItemCount() { - return mWeeksList.size(); - } - - // endregion - - // region Class - WeekViewHolder - - public class WeekViewHolder extends RecyclerView.ViewHolder { - - /** - * List of layout containers for each day - */ - private List mCells; - private TextView mTxtMonth; - private FrameLayout mMonthBackground; - - public WeekViewHolder(View itemView) { - super(itemView); - mTxtMonth = (TextView) itemView.findViewById(R.id.month_label); - mMonthBackground = (FrameLayout) itemView.findViewById(R.id.month_background); - LinearLayout daysContainer = (LinearLayout) itemView.findViewById(R.id.week_days_container); - setUpChildren(daysContainer); - } - - public void bindWeek(IWeekItem weekItem, Calendar today) { - setUpMonthOverlay(); - - List dayItems = weekItem.getDayItems(); - - for (int c = 0; c < dayItems.size(); c++) { - final IDayItem dayItem = dayItems.get(c); - LinearLayout cellItem = mCells.get(c); - TextView txtDay = (TextView) cellItem.findViewById(R.id.view_day_day_label); - TextView txtMonth = (TextView) cellItem.findViewById(R.id.view_day_month_label); - View circleView = cellItem.findViewById(R.id.view_day_circle_selected); - View eventIndicator1 = cellItem.findViewById(R.id.view_day_event_indicator1); - View eventIndicator2 = cellItem.findViewById(R.id.view_day_event_indicator2); - View eventIndicator3 = cellItem.findViewById(R.id.view_day_event_indicator3); - cellItem.setOnClickListener(v->BusProvider.getInstance().send(new Events.DayClickedEvent(dayItem))); - - eventIndicator1.setVisibility(View.INVISIBLE); - eventIndicator2.setVisibility(View.INVISIBLE); - eventIndicator3.setVisibility(View.INVISIBLE); - - Calendar dayItemCalendar = Calendar.getInstance(); - dayItemCalendar.setTime(dayItem.getDate()); - int eventCount = 0; - for (CalendarEvent event: mEventList) { - if (event.getStartTime().get(Calendar.YEAR) == dayItemCalendar.get(Calendar.YEAR) - && event.getStartTime().get(Calendar.MONTH) == dayItemCalendar.get(Calendar.MONTH) - && event.getStartTime().get(Calendar.DAY_OF_MONTH) == dayItemCalendar.get(Calendar.DAY_OF_MONTH)) { - eventCount++; - if (eventCount == 1) { - eventIndicator1.setVisibility(View.VISIBLE); - eventIndicator1.getBackground().setColorFilter(new PorterDuffColorFilter(event.getColor(),PorterDuff.Mode.MULTIPLY)); - } - if (eventCount == 2) { - eventIndicator2.setVisibility(View.VISIBLE); - eventIndicator2.getBackground().setColorFilter(new PorterDuffColorFilter(event.getColor(),PorterDuff.Mode.MULTIPLY)); - } - if (eventCount == 3) { - eventIndicator3.setVisibility(View.VISIBLE); - eventIndicator3.getBackground().setColorFilter(new PorterDuffColorFilter(event.getColor(),PorterDuff.Mode.MULTIPLY)); - } - } - } - - //Log.d("CalendarView", "Event count for day "+dayItem.getValue()+" is "+eventCount); - - txtMonth.setVisibility(View.GONE); - txtDay.setTextColor(mDayTextColor); - txtMonth.setTextColor(mDayTextColor); - circleView.setVisibility(View.GONE); - - txtDay.setTypeface(null, Typeface.NORMAL); - txtMonth.setTypeface(null, Typeface.NORMAL); - - // Display the day - txtDay.setText(Integer.toString(dayItem.getValue())); - - // Highlight first day of the month - if (dayItem.isFirstDayOfTheMonth() && !dayItem.isSelected()) { - txtMonth.setVisibility(View.VISIBLE); - txtMonth.setText(dayItem.getMonth()); - txtDay.setTypeface(null, Typeface.BOLD); - txtMonth.setTypeface(null, Typeface.BOLD); - } - - // Check if this day is in the past - if (today.getTime().after(dayItem.getDate()) && !DateHelper.sameDate(today, dayItem.getDate())) { - txtDay.setTextColor(mPastDayTextColor); - txtMonth.setTextColor(mPastDayTextColor); - } - - // Highlight the cell if this day is today - if (dayItem.isToday() && !dayItem.isSelected()) { - txtDay.setTextColor(mCurrentDayColor); - } - - if (dayItem.getShowBadge()) { - circleView.setVisibility(View.VISIBLE); - GradientDrawable drawable = (GradientDrawable) circleView.getBackground(); - drawable.setStroke((int) (2 * Resources.getSystem().getDisplayMetrics().density), 0xffff0000); - } - - // Show a circle if the day is selected - if (dayItem.isSelected()) { - txtDay.setTextColor(mDayTextColor); - circleView.setVisibility(View.VISIBLE); - GradientDrawable drawable = (GradientDrawable) circleView.getBackground(); - drawable.setStroke((int) (1 * Resources.getSystem().getDisplayMetrics().density), mDayTextColor); - } - - // Check if the month label has to be displayed - if (dayItem.getValue() == 15) { - mTxtMonth.setVisibility(View.VISIBLE); - SimpleDateFormat monthDateFormat = new SimpleDateFormat(mContext.getResources().getString(R.string.month_name_format), CalendarManager.getInstance().getLocale()); - String month = monthDateFormat.format(weekItem.getDate()).toUpperCase(); - if (today.get(Calendar.YEAR) != weekItem.getYear()) { - month = month + String.format(" %d", weekItem.getYear()); - } - mTxtMonth.setText(month); - } - } - } - - private void setUpChildren(LinearLayout daysContainer) { - mCells = new ArrayList<>(); - for (int i = 0; i < daysContainer.getChildCount(); i++) { - mCells.add((LinearLayout) daysContainer.getChildAt(i)); - } - } - - private void setUpMonthOverlay() { - mTxtMonth.setVisibility(View.GONE); - - if (isDragging()) { - AnimatorSet animatorSetFadeIn = new AnimatorSet(); - animatorSetFadeIn.setDuration(FADE_DURATION); - ObjectAnimator animatorTxtAlphaIn = ObjectAnimator.ofFloat(mTxtMonth, "alpha", mTxtMonth.getAlpha(), 1f); - ObjectAnimator animatorBackgroundAlphaIn = ObjectAnimator.ofFloat(mMonthBackground, "alpha", mMonthBackground.getAlpha(), 1f); - animatorSetFadeIn.playTogether( - animatorTxtAlphaIn - //animatorBackgroundAlphaIn - ); - animatorSetFadeIn.addListener(new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { - - } - - @Override - public void onAnimationEnd(Animator animation) { - setAlphaSet(true); - } - - @Override - public void onAnimationCancel(Animator animation) { - - } - - @Override - public void onAnimationRepeat(Animator animation) { - - } - }); - animatorSetFadeIn.start(); - } else { - AnimatorSet animatorSetFadeOut = new AnimatorSet(); - animatorSetFadeOut.setDuration(FADE_DURATION); - ObjectAnimator animatorTxtAlphaOut = ObjectAnimator.ofFloat(mTxtMonth, "alpha", mTxtMonth.getAlpha(), 0f); - ObjectAnimator animatorBackgroundAlphaOut = ObjectAnimator.ofFloat(mMonthBackground, "alpha", mMonthBackground.getAlpha(), 0f); - animatorSetFadeOut.playTogether( - animatorTxtAlphaOut - //animatorBackgroundAlphaOut - ); - animatorSetFadeOut.addListener(new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { - - } - - @Override - public void onAnimationEnd(Animator animation) { - setAlphaSet(false); - } - - @Override - public void onAnimationCancel(Animator animation) { - - } - - @Override - public void onAnimationRepeat(Animator animation) { - - } - }); - animatorSetFadeOut.start(); - } - - if (isAlphaSet()) { - //mMonthBackground.setAlpha(1f); - mTxtMonth.setAlpha(1f); - } else { - //mMonthBackground.setAlpha(0f); - mTxtMonth.setAlpha(0f); - } - } - } - - // endregion -} diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/BaseCalendarEvent.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/BaseCalendarEvent.java deleted file mode 100644 index 642eea2c..00000000 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/BaseCalendarEvent.java +++ /dev/null @@ -1,345 +0,0 @@ -package com.github.tibolte.agendacalendarview.models; - -import java.util.Calendar; - -/** - * Event model class containing the information to be displayed on the agenda view. - */ -public class BaseCalendarEvent implements CalendarEvent { - - /** - * Id of the event. - */ - private long mId; - /** - * Color to be displayed in the agenda view. - */ - private int mColor; - /** - * Text color displayed on the background color - */ - private int mTextColor; - /** - * Title of the event. - */ - private String mTitle; - /** - * Description of the event. - */ - private String mDescription; - /** - * Where the event takes place. - */ - private String mLocation; - /** - * Calendar instance helping sorting the events per section in the agenda view. - */ - private Calendar mInstanceDay; - /** - * Start time of the event. - */ - private Calendar mStartTime; - /** - * End time of the event. - */ - private Calendar mEndTime; - /** - * Indicates if the event lasts all day. - */ - private boolean mAllDay; - /** - * Tells if this BaseCalendarEvent instance is used as a placeholder in the agenda view, if there's - * no event for that day. - */ - private boolean mPlaceHolder; - /** - * Tells if this BaseCalendarEvent instance is used as a forecast information holder in the agenda - * view. - */ - private boolean mWeather; - /** - * Duration of the event. - */ - private String mDuration; - /** - * References to a DayItem instance for that event, used to link interaction between the - * calendar view and the agenda view. - */ - private IDayItem mDayReference; - /** - * References to a WeekItem instance for that event, used to link interaction between the - * calendar view and the agenda view. - */ - private IWeekItem mWeekReference; - /** - * Weather icon string returned by the Dark Sky API. - */ - private String mWeatherIcon; - /** - * Temperature value returned by the Dark Sky API. - */ - private double mTemperature; - - private boolean mShowBadge; - - // region Constructor - - /** - * Initializes the event - * - * @param id The id of the event. - * @param color The color of the event. - * @param textColor The color of the event description text. - * @param title The title of the event. - * @param description The description of the event. - * @param location The location of the event. - * @param dateStart The start date of the event. - * @param dateEnd The end date of the event. - * @param allDay Int that can be equal to 0 or 1. - * @param duration The duration of the event in RFC2445 format. - */ - public BaseCalendarEvent(long id, int color, int textColor, String title, String description, String location, long dateStart, long dateEnd, int allDay, String duration) { - this.mId = id; - this.mColor = color; - this.mTextColor = textColor; - this.mAllDay = (allDay == 1); - this.mDuration = duration; - this.mTitle = title; - this.mDescription = description; - this.mLocation = location; - - this.mStartTime = Calendar.getInstance(); - this.mStartTime.setTimeInMillis(dateStart); - this.mEndTime = Calendar.getInstance(); - this.mEndTime.setTimeInMillis(dateEnd); - } - - public BaseCalendarEvent() { - - } - - /** - * Initializes the event - * @param title The title of the event. - * @param description The description of the event. - * @param location The location of the event. - * @param color The color of the event (for display in the app). - * @param textColor The color of the event description text. - * @param startTime The start time of the event. - * @param endTime The end time of the event. - * @param allDay Indicates if the event lasts the whole day. - */ - public BaseCalendarEvent(String title, String description, String location, int color, int textColor, Calendar startTime, Calendar endTime, boolean allDay) { - this.mTitle = title; - this.mDescription = description; - this.mLocation = location; - this.mColor = color; - this.mTextColor = textColor; - this.mStartTime = startTime; - this.mEndTime = endTime; - this.mAllDay = allDay; - } - - public BaseCalendarEvent(String title, String description, String location, int color, int textColor, Calendar startTime, Calendar endTime, boolean allDay, long id, boolean showBadge) { - this.mTitle = title; - this.mDescription = description; - this.mLocation = location; - this.mColor = color; - this.mTextColor = textColor; - this.mStartTime = startTime; - this.mEndTime = endTime; - this.mAllDay = allDay; - this.mId = id; - this.mShowBadge = showBadge; - } - - public BaseCalendarEvent(BaseCalendarEvent calendarEvent) { - this.mId = calendarEvent.getId(); - this.mColor = calendarEvent.getColor(); - this.mTextColor = calendarEvent.getTextColor(); - this.mAllDay = calendarEvent.isAllDay(); - this.mDuration = calendarEvent.getDuration(); - this.mTitle = calendarEvent.getTitle(); - this.mDescription = calendarEvent.getDescription(); - this.mLocation = calendarEvent.getLocation(); - this.mStartTime = calendarEvent.getStartTime(); - this.mEndTime = calendarEvent.getEndTime(); - this.mShowBadge = calendarEvent.getShowBadge(); - } - - // endregion - - // region Getters/Setters - - public int getColor() { - return mColor; - } - - public void setColor(int mColor) { - this.mColor = mColor; - } - - public int getTextColor() { - return mTextColor; - } - - public void setTextColor(int mTextColor) { - this.mTextColor = mTextColor; - } - - public String getDescription() { - return mDescription; - } - - public boolean isAllDay() { - return mAllDay; - } - - public void setAllDay(boolean allDay) { - this.mAllDay = allDay; - } - - public void setDescription(String mDescription) { - this.mDescription = mDescription; - } - - public Calendar getInstanceDay() { - return mInstanceDay; - } - - public void setInstanceDay(Calendar mInstanceDay) { - this.mInstanceDay = mInstanceDay; - this.mInstanceDay.set(Calendar.HOUR, 0); - this.mInstanceDay.set(Calendar.MINUTE, 0); - this.mInstanceDay.set(Calendar.SECOND, 0); - this.mInstanceDay.set(Calendar.MILLISECOND, 0); - this.mInstanceDay.set(Calendar.AM_PM, 0); - } - - public Calendar getEndTime() { - return mEndTime; - } - - public void setEndTime(Calendar mEndTime) { - this.mEndTime = mEndTime; - } - public void setPlaceholder(boolean placeholder) { - mPlaceHolder = placeholder; - } - public boolean isPlaceholder() { - return mPlaceHolder; - } - - public long getId() { - return mId; - } - - public void setId(long mId) { - this.mId = mId; - } - - public boolean getShowBadge() { - return mShowBadge; - } - - public void setShowBadge(boolean mShowBadge) { - this.mShowBadge = mShowBadge; - } - - public String getLocation() { - return mLocation; - } - - public void setLocation(String mLocation) { - this.mLocation = mLocation; - } - - public Calendar getStartTime() { - return mStartTime; - } - - public void setStartTime(Calendar mStartTime) { - this.mStartTime = mStartTime; - } - - public String getTitle() { - return mTitle; - } - - public void setTitle(String mTitle) { - this.mTitle = mTitle; - } - - public String getDuration() { - return mDuration; - } - - public void setDuration(String duration) { - this.mDuration = duration; - } - - public boolean isPlaceHolder() { - return mPlaceHolder; - } - - public void setPlaceHolder(boolean mPlaceHolder) { - this.mPlaceHolder = mPlaceHolder; - } - - public boolean isWeather() { - return mWeather; - } - - public void setWeather(boolean mWeather) { - this.mWeather = mWeather; - } - - public IDayItem getDayReference() { - return mDayReference; - } - - public void setDayReference(IDayItem mDayReference) { - this.mDayReference = mDayReference; - } - - public IWeekItem getWeekReference() { - return mWeekReference; - } - - public void setWeekReference(IWeekItem mWeekReference) { - this.mWeekReference = mWeekReference; - } - - public String getWeatherIcon() { - return mWeatherIcon; - } - - public void setWeatherIcon(String mWeatherIcon) { - this.mWeatherIcon = mWeatherIcon; - } - - public double getTemperature() { - return mTemperature; - } - - public void setTemperature(double mTemperature) { - this.mTemperature = mTemperature; - } - - @Override - public CalendarEvent copy() { - return new BaseCalendarEvent(this); - } - - // endregion - - @Override - public String toString() { - return "BaseCalendarEvent{" - + "title='" - + mTitle - + ", instanceDay= " - + mInstanceDay.getTime() - + "}"; - } -} diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/CalendarEvent.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/CalendarEvent.java deleted file mode 100644 index 05df9a0f..00000000 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/CalendarEvent.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.github.tibolte.agendacalendarview.models; - -import java.util.Calendar; - -public interface CalendarEvent { - - - void setPlaceholder(boolean placeholder); - - boolean isPlaceholder(); - - public String getLocation(); - - public void setLocation(String mLocation); - - long getId(); - - void setId(long mId); - - boolean getShowBadge(); - - void setShowBadge(boolean mShowBadge); - - int getTextColor(); - - void setTextColor(int mTextColor); - - String getDescription(); - - void setDescription(String mDescription); - - boolean isAllDay(); - - void setAllDay(boolean allDay); - - Calendar getStartTime(); - - void setStartTime(Calendar mStartTime); - - Calendar getEndTime(); - - void setEndTime(Calendar mEndTime); - - String getTitle(); - - void setTitle(String mTitle); - - Calendar getInstanceDay(); - - void setInstanceDay(Calendar mInstanceDay); - - IDayItem getDayReference(); - - void setDayReference(IDayItem mDayReference); - - IWeekItem getWeekReference(); - - void setWeekReference(IWeekItem mWeekReference); - - CalendarEvent copy(); - - int getColor(); -} diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/DayItem.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/DayItem.java deleted file mode 100644 index 39be4985..00000000 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/DayItem.java +++ /dev/null @@ -1,145 +0,0 @@ -package com.github.tibolte.agendacalendarview.models; - -import com.github.tibolte.agendacalendarview.CalendarManager; -import com.github.tibolte.agendacalendarview.utils.DateHelper; - -import java.util.Calendar; -import java.util.Date; - -/** - * Day model class. - */ -public class DayItem implements IDayItem { - private Date mDate; - private int mValue; - private int mDayOfTheWeek; - private boolean mToday; - private boolean mFirstDayOfTheMonth; - private boolean mSelected; - private String mMonth; - private boolean mShowBadge; - - // region Constructor - - public DayItem(Date date, int value, boolean today, String month) { - this.mDate = date; - this.mValue = value; - this.mToday = today; - this.mMonth = month; - } - // only for cleanDay - public DayItem() { - - } - public DayItem(DayItem original) { - - this.mDate = original.getDate(); - this.mValue = original.getValue(); - this.mToday = original.isToday(); - this.mDayOfTheWeek = original.getDayOftheWeek(); - this.mFirstDayOfTheMonth = original.isFirstDayOfTheMonth(); - this.mSelected = original.isSelected(); - this.mMonth = original.getMonth(); - this.mShowBadge = original.mShowBadge; - } - // endregion - - // region Getters/Setters - - public Date getDate() { - return mDate; - } - - public void setDate(Date date) { - this.mDate = date; - } - - public int getValue() { - return mValue; - } - - public void setValue(int value) { - this.mValue = value; - } - - public boolean isToday() { - return mToday; - } - - public void setToday(boolean today) { - this.mToday = today; - } - - public boolean isSelected() { - return mSelected; - } - - public void setSelected(boolean selected) { - this.mSelected = selected; - } - - public boolean isFirstDayOfTheMonth() { - return mFirstDayOfTheMonth; - } - - public void setFirstDayOfTheMonth(boolean firstDayOfTheMonth) { - this.mFirstDayOfTheMonth = firstDayOfTheMonth; - } - - public String getMonth() { - return mMonth; - } - - public void setMonth(String month) { - this.mMonth = month; - } - - public int getDayOftheWeek() { - return mDayOfTheWeek; - } - - public void setDayOftheWeek(int mDayOftheWeek) { - this.mDayOfTheWeek = mDayOftheWeek; - } - - public void setShowBadge(boolean showBadge) { - this.mShowBadge = showBadge; - } - - public boolean getShowBadge() { - return this.mShowBadge; - } - - // region Public methods - - public void buildDayItemFromCal(Calendar calendar) { - Date date = calendar.getTime(); - this.mDate = date; - - this.mValue = calendar.get(Calendar.DAY_OF_MONTH); - this.mToday = DateHelper.sameDate(calendar, CalendarManager.getInstance().getToday()); - this.mMonth = CalendarManager.getInstance().getMonthHalfNameFormat().format(date); - if (this.mValue == 1) { - this.mFirstDayOfTheMonth = true; - } - } - - // endregion - - @Override - public String toString() { - return "DayItem{" - + "Date='" - + mDate.toString() - + ", value=" - + mValue - + '}'; - } - - @Override - public IDayItem copy() { - return new DayItem(this); - } - - // endregion -} diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/IDayItem.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/IDayItem.java deleted file mode 100644 index acfe3c76..00000000 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/IDayItem.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.github.tibolte.agendacalendarview.models; - -import java.util.Calendar; -import java.util.Date; - -public interface IDayItem { - - // region Getters/Setters - - Date getDate(); - - void setDate(Date date); - - int getValue(); - - void setValue(int value); - - boolean isToday(); - - void setToday(boolean today); - - boolean isSelected(); - - void setSelected(boolean selected); - - boolean isFirstDayOfTheMonth(); - - void setFirstDayOfTheMonth(boolean firstDayOfTheMonth); - - String getMonth(); - - void setMonth(String month); - - int getDayOftheWeek(); - - void setDayOftheWeek(int mDayOftheWeek); - - // endregion - - void buildDayItemFromCal(Calendar calendar); - - String toString(); - - IDayItem copy(); - - void setShowBadge(boolean showBadge); - - boolean getShowBadge(); -} diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/IWeekItem.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/IWeekItem.java deleted file mode 100644 index bb08b89a..00000000 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/IWeekItem.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.github.tibolte.agendacalendarview.models; - -import java.util.Date; -import java.util.List; - -public interface IWeekItem { - - - int getWeekInYear(); - - void setWeekInYear(int weekInYear); - - int getYear(); - - void setYear(int year); - - int getMonth(); - - void setMonth(int month); - - Date getDate(); - - void setDate(Date date); - - String getLabel(); - - void setLabel(String label); - - List getDayItems(); - - void setDayItems(List dayItems); - - IWeekItem copy(); -} diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/WeekItem.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/WeekItem.java deleted file mode 100644 index 40b94902..00000000 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/WeekItem.java +++ /dev/null @@ -1,110 +0,0 @@ -package com.github.tibolte.agendacalendarview.models; - -import java.util.Date; -import java.util.List; - -/** - * Week model class. - */ -public class WeekItem implements IWeekItem { - private int mWeekInYear; - private int mYear; - private int mMonth; - private Date mDate; - private String mLabel; - private List mDayItems; - - // region Constructor - - public WeekItem(int weekInYear, int year, Date date, String label, int month) { - this.mWeekInYear = weekInYear; - this.mYear = year; - this.mDate = date; - this.mLabel = label; - this.mMonth = month; - } - public WeekItem(WeekItem original) { - this.mWeekInYear = original.getWeekInYear(); - this.mYear = original.getYear(); - this.mMonth = original.getMonth(); - this.mDate = original.getDate(); - this.mLabel = original.getLabel(); - this.mDayItems = original.getDayItems(); - } - - public WeekItem(){ - - } - - // endregion - - // region Getters/Setters - - public int getWeekInYear() { - return mWeekInYear; - } - - public void setWeekInYear(int weekInYear) { - this.mWeekInYear = weekInYear; - } - - public int getYear() { - return mYear; - } - - public void setYear(int year) { - this.mYear = year; - } - - public int getMonth() { - return mMonth; - } - - public void setMonth(int month) { - this.mMonth = month; - } - - public Date getDate() { - return mDate; - } - - public void setDate(Date date) { - this.mDate = date; - } - - public String getLabel() { - return mLabel; - } - - public void setLabel(String label) { - this.mLabel = label; - } - - public List getDayItems() { - return mDayItems; - } - - public void setDayItems(List dayItems) { - this.mDayItems = dayItems; - } - - @Override - public IWeekItem copy() { - return new WeekItem(this); - } - - // endregion - - @Override - public String toString() { - return "WeekItem{" - + "label='" - + mLabel - + '\'' - + ", weekInYear=" - + mWeekInYear - + ", year=" - + mYear - + '}'; - } -} diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/render/DefaultEventRenderer.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/render/DefaultEventRenderer.java deleted file mode 100644 index 729ad706..00000000 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/render/DefaultEventRenderer.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.github.tibolte.agendacalendarview.render; - -import android.content.Context; -import android.content.res.Resources; -import androidx.annotation.NonNull; -import androidx.cardview.widget.CardView; -import androidx.core.content.ContextCompat; - -import android.graphics.Color; -import android.util.TypedValue; -import android.view.View; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.github.tibolte.agendacalendarview.R; -import com.github.tibolte.agendacalendarview.models.BaseCalendarEvent; -import com.google.android.material.internal.ViewUtils; - -/** - * Class helping to inflate our default layout in the AgendaAdapter - */ -public class DefaultEventRenderer extends EventRenderer { - - public static int themeAttributeToColor(int themeAttributeId, - Context context, - int fallbackColorId) { - TypedValue outValue = new TypedValue(); - Resources.Theme theme = context.getTheme(); - boolean wasResolved = - theme.resolveAttribute( - themeAttributeId, outValue, true); - if (wasResolved) { - return ContextCompat.getColor( - context, outValue.resourceId); - } else { - // fallback colour handling - return fallbackColorId; - } - } - - // region class - EventRenderer - - @Override - public void render(@NonNull View view, @NonNull BaseCalendarEvent event) { - CardView card = view.findViewById(R.id.view_agenda_event_card_view); - TextView txtTitle = view.findViewById(R.id.view_agenda_event_title); - TextView txtLocation = view.findViewById(R.id.view_agenda_event_location); - LinearLayout descriptionContainer = view.findViewById(R.id.view_agenda_event_description_container); - LinearLayout locationContainer = view.findViewById(R.id.view_agenda_event_location_container); - - descriptionContainer.setVisibility(View.VISIBLE); - - txtTitle.setText(event.getTitle()); - txtLocation.setText(event.getLocation()); - if (event.getLocation().length() > 0) { - locationContainer.setVisibility(View.VISIBLE); - txtLocation.setText(event.getLocation()); - } else { - locationContainer.setVisibility(View.GONE); - } - - if (!event.isPlaceholder()/*!event.getTitle().equals(view.getResources().getString(R.string.agenda_event_no_events))*/) { - txtTitle.setTextColor(event.getTextColor()); - card.setCardBackgroundColor(event.getColor()); - txtLocation.setTextColor(event.getTextColor()); - } - else { - card.setCardBackgroundColor(Color.TRANSPARENT); - card.setCardElevation(0); - card.setBackgroundColor(Color.TRANSPARENT); - card.setRadius(0); - card.setBackgroundDrawable(null); - } - } - - @Override - public int getEventLayout() { - return R.layout.view_agenda_event; - } - - // endregion -} diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/render/EventRenderer.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/render/EventRenderer.java deleted file mode 100644 index e62f23b5..00000000 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/render/EventRenderer.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.github.tibolte.agendacalendarview.render; - -import androidx.annotation.LayoutRes; -import android.view.View; - -import com.github.tibolte.agendacalendarview.models.CalendarEvent; - -import java.lang.reflect.ParameterizedType; - -/** - * Base class for helping layout rendering - */ -public abstract class EventRenderer { - public abstract void render(final View view, final T event); - - @LayoutRes - public abstract int getEventLayout(); - - public Class getRenderType() { - ParameterizedType type = (ParameterizedType) getClass().getGenericSuperclass(); - return (Class) type.getActualTypeArguments()[0]; - } -} diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/BusProvider.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/BusProvider.java deleted file mode 100644 index 99bdbf3d..00000000 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/BusProvider.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.github.tibolte.agendacalendarview.utils; - -import rx.Observable; -import rx.subjects.PublishSubject; -import rx.subjects.SerializedSubject; -import rx.subjects.Subject; - -public class BusProvider { - - public static BusProvider mInstance; - - private final Subject mBus = new SerializedSubject<>(PublishSubject.create()); - - // region Constructors - - public static BusProvider getInstance() { - if (mInstance == null) { - mInstance = new BusProvider(); - } - return mInstance; - } - - // endregion - - // region Public methods - - public void send(Object object) { - mBus.onNext(object); - } - - public Observable toObserverable() { - return mBus; - } - - // endregion -} diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/DateHelper.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/DateHelper.java deleted file mode 100644 index f9439d04..00000000 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/DateHelper.java +++ /dev/null @@ -1,135 +0,0 @@ -package com.github.tibolte.agendacalendarview.utils; - -import com.github.tibolte.agendacalendarview.CalendarManager; -import com.github.tibolte.agendacalendarview.R; -import com.github.tibolte.agendacalendarview.models.IWeekItem; - -import android.content.Context; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.Locale; -import java.util.concurrent.TimeUnit; - -/** - * Class containing helper functions for dates - */ -public class DateHelper { - - // region Public methods - - /** - * Check if two Calendar instances have the same time (by month, year and day of month) - * - * @param cal The first Calendar instance. - * @param selectedDate The second Calendar instance. - * @return True if both instances have the same time. - */ - public static boolean sameDate(Calendar cal, Calendar selectedDate) { - return cal.get(Calendar.MONTH) == selectedDate.get(Calendar.MONTH) - && cal.get(Calendar.YEAR) == selectedDate.get(Calendar.YEAR) - && cal.get(Calendar.DAY_OF_MONTH) == selectedDate.get(Calendar.DAY_OF_MONTH); - } - - /** - * Check if a Date instance and a Calendar instance have the same time (by month, year and day - * of month) - * - * @param cal The Calendar instance. - * @param selectedDate The Date instance. - * @return True if both have the same time. - */ - public static boolean sameDate(Calendar cal, Date selectedDate) { - Calendar selectedCal = Calendar.getInstance(); - selectedCal.setTime(selectedDate); - return cal.get(Calendar.MONTH) == selectedCal.get(Calendar.MONTH) - && cal.get(Calendar.YEAR) == selectedCal.get(Calendar.YEAR) - && cal.get(Calendar.DAY_OF_MONTH) == selectedCal.get(Calendar.DAY_OF_MONTH); - } - - /** - * Check if a Date instance is between two Calendar instances' dates (inclusively) in time. - * - * @param selectedDate The date to verify. - * @param startCal The start time. - * @param endCal The end time. - * @return True if the verified date is between the two specified dates. - */ - public static boolean isBetweenInclusive(Date selectedDate, Calendar startCal, Calendar endCal) { - Calendar selectedCal = Calendar.getInstance(); - selectedCal.setTime(selectedDate); - // Check if we deal with the same day regarding startCal and endCal - return sameDate(selectedCal, startCal) || selectedCal.after(startCal) && selectedCal.before(endCal); - } - - /** - * Check if Calendar instance's date is in the same week, as the WeekItem instance. - * - * @param cal The Calendar instance to verify. - * @param week The WeekItem instance to compare to. - * @return True if both instances are in the same week. - */ - public static boolean sameWeek(Calendar cal, IWeekItem week) { - return (cal.get(Calendar.WEEK_OF_YEAR) == week.getWeekInYear() && cal.get(Calendar.YEAR) == week.getYear()); - } - - /** - * Convert a millisecond duration to a string format - * - * @param millis A duration to convert to a string form - * @return A string of the form "Xd" or either "XhXm". - */ - public static String getDuration(Context context, long millis) { - if (millis < 0) { - throw new IllegalArgumentException("Duration must be greater than zero!"); - } - - long days = TimeUnit.MILLISECONDS.toDays(millis); - millis -= TimeUnit.DAYS.toMillis(days); - long hours = TimeUnit.MILLISECONDS.toHours(millis); - millis -= TimeUnit.HOURS.toMillis(hours); - long minutes = TimeUnit.MILLISECONDS.toMinutes(millis); - - StringBuilder sb = new StringBuilder(64); - if (days > 0) { - sb.append(days); - sb.append(context.getResources().getString(R.string.agenda_event_day_duration)); - return (sb.toString()); - } else { - if (hours > 0) { - sb.append(hours); - sb.append("h"); - } - if (minutes > 0) { - sb.append(minutes); - sb.append("m"); - } - } - - return (sb.toString()); - } - - /** - * Used for displaying the date in any section of the agenda view. - * - * @param calendar The date of the section. - * @param locale The locale used by the Sunrise calendar. - * @return The formatted date without the year included. - */ - public static String getYearLessLocalizedDate(Calendar calendar, Locale locale) { - SimpleDateFormat sdf = (SimpleDateFormat) SimpleDateFormat.getDateInstance(DateFormat.FULL, CalendarManager.getInstance().getLocale()); - String pattern = sdf.toPattern(); - - String yearLessPattern = pattern.replaceAll("\\W?[Yy]+\\W?", ""); - SimpleDateFormat yearLessSDF = new SimpleDateFormat(yearLessPattern, locale); - String yearLessDate = yearLessSDF.format(calendar.getTime()).toUpperCase(); - if (yearLessDate.endsWith(",")) { - yearLessDate = yearLessDate.substring(0, yearLessDate.length() - 1); - } - return yearLessDate; - } - - // endregion -} diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/Events.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/Events.java deleted file mode 100644 index 98d13f20..00000000 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/Events.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.github.tibolte.agendacalendarview.utils; - -import com.github.tibolte.agendacalendarview.models.IDayItem; - -import java.util.Calendar; - -/** - * Events emitted by the bus provider. - */ -public class Events { - - public static class DayClickedEvent { - - public Calendar mCalendar; - public IDayItem mDayItem; - - public DayClickedEvent(IDayItem dayItem) { - this.mCalendar = Calendar.getInstance(); - this.mCalendar.setTime(dayItem.getDate()); - this.mDayItem = dayItem; - } - - public Calendar getCalendar() { - return mCalendar; - } - - public IDayItem getDay() { - return mDayItem; - } - } - - public static class CalendarScrolledEvent { - } - - public static class AgendaListViewTouchedEvent { - } - - public static class EventsFetched { - } - - public static class ForecastFetched { - } -} diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/ListViewScrollTracker.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/ListViewScrollTracker.java deleted file mode 100644 index 47e16de3..00000000 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/ListViewScrollTracker.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.github.tibolte.agendacalendarview.utils; - -import com.github.tibolte.agendacalendarview.agenda.AgendaListView; - -import android.util.SparseArray; -import android.view.View; - -/** - * Helper class calculating the scrolling distance in the AgendaListView. - */ -public class ListViewScrollTracker { - private AgendaListView mListView; - private SparseArray mPositions; - private SparseArray mListViewItemHeights = new SparseArray<>(); - private int mFirstVisiblePosition; - private int mReferencePosition = -1; // Position of the current date in the Agenda listView - - // region Constructor and Accessor(s) - - public ListViewScrollTracker(AgendaListView listView) { - mListView = listView; - } - - public int getReferencePosition() { - return mReferencePosition; - } - - // endregion - - // region Public methods - - /** - * Call from an AbsListView.OnScrollListener to calculate the incremental offset (change in - * scroll offset - * since the last calculation). - * - * @param firstVisiblePosition First visible item position in the list. - * @param visibleItemCount Number of visible items in the list. - * @return The incremental offset, or 0 if it wasn't possible to calculate the offset. - */ - public int calculateIncrementalOffset(int firstVisiblePosition, int visibleItemCount) { - // Remember previous positions, if any - SparseArray previousPositions = mPositions; - - // Store new positions - mPositions = new SparseArray<>(); - for (int i = 0; i < visibleItemCount; i++) { - mPositions.put(firstVisiblePosition + i, mListView.getListChildAt(i).getTop()); - } - - if (previousPositions != null) { - // Find position which exists in both mPositions and previousPositions, then return the difference - // of the new and old Y values. - for (int i = 0; i < previousPositions.size(); i++) { - int previousPosition = previousPositions.keyAt(i); - int previousTop = previousPositions.get(previousPosition); - Integer newTop = mPositions.get(previousPosition); - if (newTop != null) { - return newTop - previousTop; - } - } - } - - return 0; // No view's position was in both previousPositions and mPositions - } - - /** - * Call from an AbsListView.OnScrollListener to calculate the scrollY (Here - * we definite as the distance in pixels compared to the position representing the current - * date). - * - * @param firstVisiblePosition First visible item position in the list. - * @param visibleItemCount Number of visible items in the list. - * @return Distance in pixels compared to current day position (negative if firstVisiblePosition less than mReferencePosition) - */ - public int calculateScrollY(int firstVisiblePosition, int visibleItemCount) { - mFirstVisiblePosition = firstVisiblePosition; - if (mReferencePosition < 0) { - mReferencePosition = mFirstVisiblePosition; - } - - if (visibleItemCount > 0) { - View c = mListView.getListChildAt(0); // this is the first visible row - int scrollY = -c.getTop(); - mListViewItemHeights.put(firstVisiblePosition, c.getMeasuredHeight()); - - if (mFirstVisiblePosition >= mReferencePosition) { - for (int i = mReferencePosition; i < firstVisiblePosition; ++i) { - if (mListViewItemHeights.get(i) == null) { - mListViewItemHeights.put(i, c.getMeasuredHeight()); - } - scrollY += mListViewItemHeights.get(i); // add all heights of the views that are gone - } - return scrollY; - } else { - for (int i = mReferencePosition - 1; i >= firstVisiblePosition; --i) { - if (mListViewItemHeights.get(i) == null) { - mListViewItemHeights.put(i, c.getMeasuredHeight()); - } - scrollY -= mListViewItemHeights.get(i); - } - return scrollY; - } - - } - return 0; - } - - public void clear() { - mPositions = null; - } - - // endregion -} diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/widgets/FloatingActionButton.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/widgets/FloatingActionButton.java deleted file mode 100644 index bd008910..00000000 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/widgets/FloatingActionButton.java +++ /dev/null @@ -1,110 +0,0 @@ -package com.github.tibolte.agendacalendarview.widgets; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.ViewGroup; -import android.view.ViewTreeObserver; -import android.view.animation.AccelerateDecelerateInterpolator; -import android.view.animation.Interpolator; - -/** - * Floating action button helping to scroll back to the current date. - */ -public class FloatingActionButton extends com.google.android.material.floatingactionbutton.FloatingActionButton { - private static final int TRANSLATE_DURATION_MILLIS = 200; - - private boolean mVisible = true; - - private final Interpolator mInterpolator = new AccelerateDecelerateInterpolator(); - - // region Constructors - - public FloatingActionButton(Context context) { - super(context); - } - - public FloatingActionButton(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public FloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - // endregion - - // region Overrides - - @Override - public void show() { - show(true); - } - - @Override - public void hide() { - hide(true); - } - - // endregion - - // region Public methods - - public void show(boolean animate) { - toggle(true, animate, false); - } - - public void hide(boolean animate) { - toggle(false, animate, false); - } - - public boolean isVisible() { - return mVisible; - } - - // endregion - - // region Private methods - - private void toggle(final boolean visible, final boolean animate, boolean force) { - if (mVisible != visible || force) { - mVisible = visible; - int height = getHeight(); - if (height == 0 && !force) { - ViewTreeObserver vto = getViewTreeObserver(); - if (vto.isAlive()) { - vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - ViewTreeObserver currentVto = getViewTreeObserver(); - if (currentVto.isAlive()) { - currentVto.removeOnPreDrawListener(this); - } - toggle(visible, animate, true); - return true; - } - }); - return; - } - } - int translationY = visible ? 0 : height + getMarginBottom(); - if (animate) { - animate().setInterpolator(mInterpolator) - .setDuration(TRANSLATE_DURATION_MILLIS) - .translationY(translationY); - } else { - setTranslationY(translationY); - } - } - } - - private int getMarginBottom() { - int marginBottom = 0; - final ViewGroup.LayoutParams layoutParams = getLayoutParams(); - if (layoutParams instanceof ViewGroup.MarginLayoutParams) { - marginBottom = ((ViewGroup.MarginLayoutParams) layoutParams).bottomMargin; - } - return marginBottom; - } - - // endregion -} diff --git a/agendacalendarview/src/main/res/drawable/agenda_day_circle.xml b/agendacalendarview/src/main/res/drawable/agenda_day_circle.xml deleted file mode 100644 index e1398e00..00000000 --- a/agendacalendarview/src/main/res/drawable/agenda_day_circle.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/agendacalendarview/src/main/res/drawable/event_color_circle.xml b/agendacalendarview/src/main/res/drawable/event_color_circle.xml deleted file mode 100644 index 3cc72359..00000000 --- a/agendacalendarview/src/main/res/drawable/event_color_circle.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/agendacalendarview/src/main/res/drawable/fab_arrow.xml b/agendacalendarview/src/main/res/drawable/fab_arrow.xml deleted file mode 100644 index 3b4d3a8c..00000000 --- a/agendacalendarview/src/main/res/drawable/fab_arrow.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - \ No newline at end of file diff --git a/agendacalendarview/src/main/res/drawable/selected_day_color_circle.xml b/agendacalendarview/src/main/res/drawable/selected_day_color_circle.xml deleted file mode 100644 index 3d53cf8c..00000000 --- a/agendacalendarview/src/main/res/drawable/selected_day_color_circle.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/agendacalendarview/src/main/res/drawable/shadow.xml b/agendacalendarview/src/main/res/drawable/shadow.xml deleted file mode 100644 index 7ab76207..00000000 --- a/agendacalendarview/src/main/res/drawable/shadow.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file diff --git a/agendacalendarview/src/main/res/layout/list_item_week.xml b/agendacalendarview/src/main/res/layout/list_item_week.xml deleted file mode 100644 index 846ba637..00000000 --- a/agendacalendarview/src/main/res/layout/list_item_week.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/agendacalendarview/src/main/res/layout/view_agenda.xml b/agendacalendarview/src/main/res/layout/view_agenda.xml deleted file mode 100644 index 5f4a704e..00000000 --- a/agendacalendarview/src/main/res/layout/view_agenda.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/agendacalendarview/src/main/res/layout/view_agenda_event.xml b/agendacalendarview/src/main/res/layout/view_agenda_event.xml deleted file mode 100644 index 92329386..00000000 --- a/agendacalendarview/src/main/res/layout/view_agenda_event.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/agendacalendarview/src/main/res/layout/view_agenda_header.xml b/agendacalendarview/src/main/res/layout/view_agenda_header.xml deleted file mode 100644 index e0391dd5..00000000 --- a/agendacalendarview/src/main/res/layout/view_agenda_header.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/agendacalendarview/src/main/res/layout/view_agendacalendar.xml b/agendacalendarview/src/main/res/layout/view_agendacalendar.xml deleted file mode 100644 index e2df4255..00000000 --- a/agendacalendarview/src/main/res/layout/view_agendacalendar.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/agendacalendarview/src/main/res/layout/view_calendar.xml b/agendacalendarview/src/main/res/layout/view_calendar.xml deleted file mode 100644 index 4b3839e0..00000000 --- a/agendacalendarview/src/main/res/layout/view_calendar.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/agendacalendarview/src/main/res/layout/view_day_calendar_header.xml b/agendacalendarview/src/main/res/layout/view_day_calendar_header.xml deleted file mode 100644 index 2326af49..00000000 --- a/agendacalendarview/src/main/res/layout/view_day_calendar_header.xml +++ /dev/null @@ -1,9 +0,0 @@ - - \ No newline at end of file diff --git a/agendacalendarview/src/main/res/layout/view_day_cell.xml b/agendacalendarview/src/main/res/layout/view_day_cell.xml deleted file mode 100644 index cebb97db..00000000 --- a/agendacalendarview/src/main/res/layout/view_day_cell.xml +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/agendacalendarview/src/main/res/values-en/strings.xml b/agendacalendarview/src/main/res/values-en/strings.xml deleted file mode 100644 index 1d9b1040..00000000 --- a/agendacalendarview/src/main/res/values-en/strings.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - Today - Tomorrow - d - All day - No events - - - LLLL - MMM - diff --git a/agendacalendarview/src/main/res/values/attrs.xml b/agendacalendarview/src/main/res/values/attrs.xml deleted file mode 100644 index 6750df84..00000000 --- a/agendacalendarview/src/main/res/values/attrs.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/agendacalendarview/src/main/res/values/colors.xml b/agendacalendarview/src/main/res/values/colors.xml deleted file mode 100644 index 7904509d..00000000 --- a/agendacalendarview/src/main/res/values/colors.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - #000000 - #9C9CA0 - #CCFFFFFF - #F3F3F3 - - - - #00000000 - - - #2196F3 - #1976D2 - #2196F3 - #BBDEFB - #4caf50 - #FFFFFF - - \ No newline at end of file diff --git a/agendacalendarview/src/main/res/values/dimens.xml b/agendacalendarview/src/main/res/values/dimens.xml deleted file mode 100644 index 7b639f8d..00000000 --- a/agendacalendarview/src/main/res/values/dimens.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - 20dp - 52dp - 14dp - 32dp - - - 60dp - - - - - 70dp - 5dp - 15dp - 5dp - \ No newline at end of file diff --git a/agendacalendarview/src/main/res/values/strings.xml b/agendacalendarview/src/main/res/values/strings.xml deleted file mode 100644 index 7c2c5f8a..00000000 --- a/agendacalendarview/src/main/res/values/strings.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - LLLL - E - - - Dziś - Jutro - d - Cały dzień - Brak wydarzeń - - MMM - diff --git a/agendacalendarview/src/main/res/values/styles.xml b/agendacalendarview/src/main/res/values/styles.xml deleted file mode 100644 index b4bf4679..00000000 --- a/agendacalendarview/src/main/res/values/styles.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index d6ccb59b..7b2c0b9a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -163,11 +163,9 @@ dependencies { implementation "org.greenrobot:eventbus:3.1.1" implementation "org.jsoup:jsoup:1.12.1" implementation "pl.droidsonroids.gif:android-gif-drawable:1.2.15" - //implementation "se.emilsjolander:stickylistheaders:2.7.0" - implementation 'com.github.edisonw:StickyListHeaders:master-SNAPSHOT@aar' implementation "uk.co.samuelwall:material-tap-target-prompt:2.14.0" - implementation project(":agendacalendarview") + implementation "eu.szkolny:agendacalendarview:1799f8ef47" implementation "eu.szkolny:cafebar:5bf0c618de" implementation "eu.szkolny:material-about-library:0534abf316" implementation "eu.szkolny:mhttp:af4b62e6e9" diff --git a/settings.gradle b/settings.gradle index b47390e3..680b7d04 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,7 +3,7 @@ include ':wear' include ':codegen' include ':annotation' rootProject.name='Szkolny.eu' -include ':app', ':agendacalendarview', ':szkolny-font' +include ':app', ':szkolny-font' /* include ':Navigation' project(':Navigation').projectDir = new File(settingsDir, '../Navigation/navlib')*/ From e91d99652c1395bc5f95a0b25691fdf6f3951b80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 21 Mar 2021 14:36:30 +0100 Subject: [PATCH 009/113] [Gradle] Extract szkolny-font dependency. Migrate Iconics to v5. --- app/build.gradle | 9 +- .../java/pl/szczodrzynski/edziennik/App.kt | 2 - .../szczodrzynski/edziennik/MainActivity.kt | 12 +- .../ui/modules/agenda/AgendaFragment.kt | 15 +- .../ui/modules/behaviour/NoticesAdapter.kt | 29 ++- .../ui/modules/home/CounterActivity.kt | 11 +- .../edziennik/ui/modules/home/HomeFragment.kt | 7 +- .../modules/home/cards/HomeTimetableCard.kt | 29 ++- .../ui/modules/homework/HomeworkFragment.kt | 2 +- .../ui/modules/login/LoginFormFragment.kt | 11 +- .../ui/modules/messages/MessageFragment.kt | 7 +- .../settings/SettingsLicenseActivity.kt | 9 +- .../modules/settings/SettingsNewFragment.java | 207 +++++------------ .../ui/modules/timetable/TimetableFragment.kt | 2 +- .../ui/modules/views/AttachmentAdapter.kt | 25 ++- .../WidgetNotificationsProvider.kt | 8 +- .../timetable/WidgetTimetableFactory.java | 20 +- .../timetable/WidgetTimetableProvider.kt | 20 +- .../utils/SwipeRefreshLayoutNoIndicator.java | 208 ++++++++++++++++++ .../utils/SwipeRefreshLayoutNoTouch.java | 51 +++++ build.gradle | 2 +- settings.gradle | 2 +- szkolny-font/build.gradle | 50 ----- szkolny-font/consumer-proguard-rules.pro | 1 - szkolny-font/gradle.properties | 40 ---- szkolny-font/src/main/AndroidManifest.xml | 19 -- .../library/szkolny/font/SzkolnyFont.kt | 87 -------- .../main/res/font/szkolny_font_font_v1_1.ttf | Bin 11232 -> 0 bytes .../src/main/res/values/font_addon.xml | 2 - 29 files changed, 441 insertions(+), 446 deletions(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/utils/SwipeRefreshLayoutNoIndicator.java create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/utils/SwipeRefreshLayoutNoTouch.java delete mode 100644 szkolny-font/build.gradle delete mode 100644 szkolny-font/consumer-proguard-rules.pro delete mode 100644 szkolny-font/gradle.properties delete mode 100644 szkolny-font/src/main/AndroidManifest.xml delete mode 100644 szkolny-font/src/main/java/com/mikepenz/iconics/typeface/library/szkolny/font/SzkolnyFont.kt delete mode 100644 szkolny-font/src/main/res/font/szkolny_font_font_v1_1.ttf delete mode 100644 szkolny-font/src/main/res/values/font_addon.xml diff --git a/app/build.gradle b/app/build.gradle index 7b2c0b9a..4ad2fc5f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -127,14 +127,9 @@ dependencies { implementation "com.google.android.material:material:${versions.material}" implementation "com.google.firebase:firebase-messaging:${versions.firebasemessaging}" - //implementation "com.github.kuba2k2.MaterialDrawer:library:e603091449" - implementation "com.mikepenz:crossfader:1.6.0" // do not update - implementation "com.mikepenz:iconics-core:${versions.iconics}" + implementation "pl.szczodrzynski:NavLib:v0.7.0" implementation "com.mikepenz:iconics-views:${versions.iconics}" implementation "com.mikepenz:community-material-typeface:${versions.font_cmd}@aar" - implementation "com.mikepenz:materialize:1.2.1" - - implementation "com.github.kuba2k2:NavLib:${versions.navlib}" implementation "com.afollestad.material-dialogs:commons:${versions.materialdialogs}" implementation "com.afollestad.material-dialogs:core:${versions.materialdialogs}" @@ -171,7 +166,7 @@ dependencies { implementation "eu.szkolny:mhttp:af4b62e6e9" implementation "eu.szkolny:nachos:0e5dfcaceb" //implementation project(":Navigation") - implementation project(":szkolny-font") + implementation "eu.szkolny:szkolny-font:1dab7d64ed" implementation "com.github.ChuckerTeam.Chucker:library:3.0.1" //releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:3.0.1" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/App.kt b/app/src/main/java/pl/szczodrzynski/edziennik/App.kt index 88bdc603..0bc6f2e0 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/App.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/App.kt @@ -26,7 +26,6 @@ import com.google.firebase.messaging.FirebaseMessaging import com.google.gson.Gson import com.hypertrack.hyperlog.HyperLog import com.mikepenz.iconics.Iconics -import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont import im.wangchao.mhttp.MHttp import kotlinx.coroutines.* import me.leolin.shortcutbadger.ShortcutBadger @@ -159,7 +158,6 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope { .errorActivity(CrashActivity::class.java) .apply() Iconics.init(applicationContext) - Iconics.registerFont(SzkolnyFont) App.db = AppDb(this) Themes.themeInt = config.ui.theme devMode = config.debugMode diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt index 084cace6..099763d2 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt @@ -23,16 +23,16 @@ import androidx.lifecycle.Observer import androidx.navigation.NavOptions import com.danimahardhika.cafebar.CafeBar import com.google.android.material.dialog.MaterialAlertDialogBuilder -import com.mikepenz.iconics.IconicsColor import com.mikepenz.iconics.IconicsDrawable -import com.mikepenz.iconics.IconicsSize import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial -import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont +import com.mikepenz.iconics.utils.colorInt +import com.mikepenz.iconics.utils.sizeDp import com.mikepenz.materialdrawer.model.DividerDrawerItem import com.mikepenz.materialdrawer.model.ProfileDrawerItem import com.mikepenz.materialdrawer.model.ProfileSettingDrawerItem import com.mikepenz.materialdrawer.model.interfaces.* import com.mikepenz.materialdrawer.model.utils.withIsHiddenInMiniDrawer +import eu.szkolny.font.SzkolnyFont import kotlinx.coroutines.* import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe @@ -519,7 +519,11 @@ class MainActivity : AppCompatActivity(), CoroutineScope { navView.coordinator.postDelayed({ CafeBar.builder(this) .content(R.string.rate_snackbar_text) - .icon(IconicsDrawable(this).icon(CommunityMaterial.Icon2.cmd_star_outline).size(IconicsSize.dp(20)).color(IconicsColor.colorInt(Themes.getPrimaryTextColor(this)))) + .icon(IconicsDrawable(this).apply { + icon = CommunityMaterial.Icon2.cmd_star_outline + sizeDp = 20 + colorInt = Themes.getPrimaryTextColor(this@MainActivity) + }) .positiveText(R.string.rate_snackbar_positive) .positiveColor(-0xb350b0) .negativeText(R.string.rate_snackbar_negative) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/agenda/AgendaFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/agenda/AgendaFragment.kt index ec212cea..35750f43 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/agenda/AgendaFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/agenda/AgendaFragment.kt @@ -16,12 +16,12 @@ import com.github.tibolte.agendacalendarview.CalendarPickerController import com.github.tibolte.agendacalendarview.models.BaseCalendarEvent import com.github.tibolte.agendacalendarview.models.CalendarEvent import com.github.tibolte.agendacalendarview.models.IDayItem -import com.mikepenz.iconics.IconicsColor import com.mikepenz.iconics.IconicsDrawable -import com.mikepenz.iconics.IconicsSize import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial.Icon2 -import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont +import com.mikepenz.iconics.utils.colorInt +import com.mikepenz.iconics.utils.sizeDp +import eu.szkolny.font.SzkolnyFont import kotlinx.coroutines.* import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.MainActivity @@ -278,10 +278,11 @@ class AgendaFragment : Fragment(), CoroutineScope { val unreadEventDates = mutableSetOf() events.forEach { event -> - val eventIcon = IconicsDrawable(activity) - .icon(CommunityMaterial.Icon.cmd_checkbox_blank_circle) - .size(IconicsSize.dp(10)) - .color(IconicsColor.colorInt(event.eventColor)) + val eventIcon = IconicsDrawable(activity).apply { + icon = CommunityMaterial.Icon.cmd_checkbox_blank_circle + sizeDp = 10 + colorInt = event.eventColor + } dayList.add(EventDay(event.startTimeCalendar, eventIcon)) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/behaviour/NoticesAdapter.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/behaviour/NoticesAdapter.kt index f495d61e..93f21191 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/behaviour/NoticesAdapter.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/behaviour/NoticesAdapter.kt @@ -13,9 +13,9 @@ import androidx.cardview.widget.CardView import androidx.recyclerview.widget.RecyclerView import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial -import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont import com.mikepenz.iconics.utils.colorRes import com.mikepenz.iconics.utils.sizeDp +import eu.szkolny.font.SzkolnyFont import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_MOBIDZIENNIK @@ -49,17 +49,26 @@ class NoticesAdapter//getting the context and product list with constructor holder.noticesItemAddedDate.text = Date.fromMillis(notice.addedDate).formattedString if (notice.type == Notice.TYPE_POSITIVE) { - holder.noticesItemType.setImageDrawable(IconicsDrawable(context, CommunityMaterial.Icon2.cmd_plus_circle_outline) - .colorRes(R.color.md_green_600) - .sizeDp(36)) + holder.noticesItemType.setImageDrawable( + IconicsDrawable(context, CommunityMaterial.Icon2.cmd_plus_circle_outline).apply { + colorRes = R.color.md_green_600 + sizeDp = 36 + } + ) } else if (notice.type == Notice.TYPE_NEGATIVE) { - holder.noticesItemType.setImageDrawable(IconicsDrawable(context, CommunityMaterial.Icon.cmd_alert_decagram_outline) - .colorRes(R.color.md_red_600) - .sizeDp(36)) + holder.noticesItemType.setImageDrawable( + IconicsDrawable(context, CommunityMaterial.Icon.cmd_alert_decagram_outline).apply { + colorRes = R.color.md_red_600 + sizeDp = 36 + } + ) } else { - holder.noticesItemType.setImageDrawable(IconicsDrawable(context, SzkolnyFont.Icon.szf_message_processing_outline) - .colorRes(R.color.md_blue_500) - .sizeDp(36)) + holder.noticesItemType.setImageDrawable( + IconicsDrawable(context, SzkolnyFont.Icon.szf_message_processing_outline).apply { + colorRes = R.color.md_blue_500 + sizeDp = 36 + } + ) } if (!notice.seen) { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/CounterActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/CounterActivity.kt index e337f720..868b330f 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/CounterActivity.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/CounterActivity.kt @@ -7,9 +7,9 @@ package pl.szczodrzynski.edziennik.ui.modules.home import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import com.mikepenz.iconics.IconicsDrawable -import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont import com.mikepenz.iconics.utils.colorInt import com.mikepenz.iconics.utils.sizeDp +import eu.szkolny.font.SzkolnyFont import kotlinx.coroutines.* import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.db.entity.Lesson @@ -59,9 +59,12 @@ class CounterActivity : AppCompatActivity(), CoroutineScope { } } - b.bellSync.setImageDrawable(IconicsDrawable(this@CounterActivity, SzkolnyFont.Icon.szf_alarm_bell_outline) - .colorInt(0xff404040.toInt()) - .sizeDp(36)) + b.bellSync.setImageDrawable( + IconicsDrawable(this@CounterActivity, SzkolnyFont.Icon.szf_alarm_bell_outline).apply { + colorInt = 0xff404040.toInt() + sizeDp = 36 + } + ) b.bellSync.onClick { BellSyncTimeChooseDialog(activity = this@CounterActivity) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/HomeFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/HomeFragment.kt index 8afd7c04..944c60e8 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/HomeFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/HomeFragment.kt @@ -19,14 +19,13 @@ import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial.Icon -import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont +import eu.szkolny.font.SzkolnyFont import kotlinx.coroutines.* import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.db.entity.LoginStore import pl.szczodrzynski.edziennik.databinding.FragmentHomeBinding import pl.szczodrzynski.edziennik.ui.dialogs.home.StudentNumberDialog import pl.szczodrzynski.edziennik.ui.modules.home.cards.* -import pl.szczodrzynski.edziennik.utils.Themes import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem import kotlin.coroutines.CoroutineContext @@ -75,7 +74,7 @@ class HomeFragment : Fragment(), CoroutineScope { private lateinit var activity: MainActivity private lateinit var b: FragmentHomeBinding - private lateinit var job: Job + private val job: Job = Job() override val coroutineContext: CoroutineContext get() = job + Dispatchers.Main @@ -83,10 +82,8 @@ class HomeFragment : Fragment(), CoroutineScope { activity = (getActivity() as MainActivity?) ?: return null context ?: return null app = activity.application as App - context!!.theme.applyStyle(Themes.appTheme, true) b = FragmentHomeBinding.inflate(inflater) b.refreshLayout.setParent(activity.swipeRefreshLayout) - job = Job() return b.root } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/cards/HomeTimetableCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/cards/HomeTimetableCard.kt index 68363ec6..a530eefc 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/cards/HomeTimetableCard.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/cards/HomeTimetableCard.kt @@ -15,8 +15,8 @@ import androidx.core.view.setMargins import androidx.lifecycle.Observer import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial -import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont import com.mikepenz.iconics.utils.sizeDp +import eu.szkolny.font.SzkolnyFont import kotlinx.coroutines.* import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe @@ -87,17 +87,26 @@ class HomeTimetableCard( } holder.root += b.root - b.settings.setImageDrawable(IconicsDrawable(activity, CommunityMaterial.Icon2.cmd_settings_outline) - .colorAttr(activity, R.attr.colorIcon) - .sizeDp(20)) + b.settings.setImageDrawable( + IconicsDrawable(activity, CommunityMaterial.Icon2.cmd_settings_outline).apply { + colorAttr(activity, R.attr.colorIcon) + sizeDp = 20 + } + ) - b.bellSync.setImageDrawable(IconicsDrawable(activity, SzkolnyFont.Icon.szf_alarm_bell_outline) - .colorAttr(activity, R.attr.colorIcon) - .sizeDp(20)) + b.bellSync.setImageDrawable( + IconicsDrawable(activity, SzkolnyFont.Icon.szf_alarm_bell_outline).apply { + colorAttr(activity, R.attr.colorIcon) + sizeDp = 20 + } + ) - b.showCounter.setImageDrawable(IconicsDrawable(activity, CommunityMaterial.Icon.cmd_fullscreen) - .colorAttr(activity, R.attr.colorIcon) - .sizeDp(20)) + b.showCounter.setImageDrawable( + IconicsDrawable(activity, CommunityMaterial.Icon.cmd_fullscreen).apply { + colorAttr(activity, R.attr.colorIcon) + sizeDp = 20 + } + ) b.bellSync.setOnClickListener { BellSyncTimeChooseDialog( diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/homework/HomeworkFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/homework/HomeworkFragment.kt index 30abcd02..f757570a 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/homework/HomeworkFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/homework/HomeworkFragment.kt @@ -12,7 +12,7 @@ import android.view.ViewGroup import android.widget.Toast import androidx.fragment.app.Fragment import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial -import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont +import eu.szkolny.font.SzkolnyFont import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginFormFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginFormFragment.kt index 8776f355..9e00200b 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginFormFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginFormFragment.kt @@ -97,11 +97,12 @@ class LoginFormFragment : Fragment(), CoroutineScope { b.textEdit.id = credential.name b.textEdit.setText(arguments?.getString(credential.keyName) ?: "") - b.textLayout.startIconDrawable = IconicsDrawable(activity) - .icon(credential.icon) - .sizeDp(24) - .paddingDp(2) - .colorAttr(activity, R.attr.colorOnBackground) + b.textLayout.startIconDrawable = IconicsDrawable(activity).apply { + icon = credential.icon + sizeDp = 24 + paddingDp = 2 + colorAttr(activity, R.attr.colorOnBackground) + } this.b.formContainer.addView(b.root) credentials[credential] = b diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessageFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessageFragment.kt index b2623b64..19106004 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessageFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessageFragment.kt @@ -65,9 +65,10 @@ class MessageFragment : Fragment(), CoroutineScope { if (!isAdded) return b.closeButton.setImageDrawable( - IconicsDrawable(activity, CommunityMaterial.Icon2.cmd_window_close) - .colorAttr(activity, android.R.attr.textColorSecondary) - .sizeDp(12) + IconicsDrawable(activity, CommunityMaterial.Icon2.cmd_window_close).apply { + colorAttr(activity, android.R.attr.textColorSecondary) + sizeDp = 12 + } ) b.closeButton.setOnClickListener { activity.navigateUp() } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsLicenseActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsLicenseActivity.kt index eb1a23e1..192f1273 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsLicenseActivity.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsLicenseActivity.kt @@ -38,10 +38,11 @@ class SettingsLicenseActivity : MaterialAboutActivity() { license: OpenSourceLicense, libraryUrl: String): MaterialAboutCard { val licenseItem = MaterialAboutActionItem.Builder() - .icon(IconicsDrawable(this) - .icon(CommunityMaterial.Icon.cmd_book_outline) - .colorInt(foregroundColor) - .sizeDp(18)) + .icon(IconicsDrawable(this).apply { + icon = CommunityMaterial.Icon.cmd_book_outline + colorInt = foregroundColor + sizeDp = 18 + }) .setIconGravity(MaterialAboutActionItem.GRAVITY_TOP) .text(libraryTitle) .subText(String.format(getString(license.resourceId), copyrightYear, copyrightName)) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java index e1541d54..3a6bffe4 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java @@ -25,11 +25,11 @@ import com.danielstone.materialaboutlibrary.items.MaterialAboutSwitchItem; import com.danielstone.materialaboutlibrary.items.MaterialAboutTitleItem; import com.danielstone.materialaboutlibrary.model.MaterialAboutCard; import com.danielstone.materialaboutlibrary.model.MaterialAboutList; -import com.mikepenz.iconics.IconicsColor; import com.mikepenz.iconics.IconicsDrawable; -import com.mikepenz.iconics.IconicsSize; +import com.mikepenz.iconics.typeface.IIcon; import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial; -import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont; +import com.mikepenz.iconics.utils.IconicsConvertersKt; +import com.mikepenz.iconics.utils.IconicsDrawableExtensionsKt; import com.theartofdev.edmodo.cropper.CropImage; import com.theartofdev.edmodo.cropper.CropImageView; import com.wdullaer.materialdatetimepicker.time.TimePickerDialog; @@ -40,6 +40,8 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import eu.szkolny.font.SzkolnyFont; +import kotlin.Unit; import pl.szczodrzynski.edziennik.App; import pl.szczodrzynski.edziennik.BuildConfig; import pl.szczodrzynski.edziennik.ExtensionsKt; @@ -90,6 +92,15 @@ public class SettingsNewFragment extends MaterialAboutFragment { private int secondaryTextOnPrimaryBg = -1; private int iconSizeDp = 20; + private IconicsDrawable icon(IIcon icon, int sizeDp, int color) { + return new IconicsDrawable(activity).apply((drawable) -> { + drawable.setIcon(icon); + IconicsConvertersKt.setSizeDp(drawable, sizeDp); + IconicsDrawableExtensionsKt.setColorInt(drawable, color); + return Unit.INSTANCE; + }); + } + private MaterialAboutCard getCardWithItems(CharSequence title, ArrayList items, boolean primaryColor) { MaterialAboutCard card = new MaterialAboutCard.Builder().title(title).cardColor(0xff1976D2).build(); card.getItems().addAll(items); @@ -120,10 +131,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { return new MaterialAboutActionItem( getString(R.string.settings_more_text), null, - new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon.cmd_chevron_down) - .size(IconicsSize.dp(14)) - .color(IconicsColor.colorInt(iconColor)), + icon(CommunityMaterial.Icon.cmd_chevron_down, 14, iconColor), onClickAction ); } @@ -209,10 +217,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { new MaterialAboutActionItem( getString(R.string.settings_profile_change_password_text), getString(R.string.settings_profile_change_password_subtext), - new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon2.cmd_key_variant) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) + icon(CommunityMaterial.Icon2.cmd_key_variant, iconSizeDp, iconColor) ) .setOnClickAction(() -> { @@ -223,10 +228,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { new MaterialAboutActionItem( getString(R.string.settings_add_student_text), getString(R.string.settings_add_student_subtext), - new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon.cmd_account_plus_outline) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) + icon(CommunityMaterial.Icon.cmd_account_plus_outline, iconSizeDp, iconColor) ) .setOnClickAction(() -> { startActivity(new Intent(activity, LoginActivity.class)); @@ -237,10 +239,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { new MaterialAboutActionItem( getString(R.string.settings_profile_notifications_text), getString(R.string.settings_profile_notifications_subtext), - new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon.cmd_filter_outline) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) + icon(CommunityMaterial.Icon.cmd_filter_outline, iconSizeDp, iconColor) ) .setOnClickAction(() -> { new NotificationFilterDialog(activity, null, null); @@ -251,10 +250,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { new MaterialAboutActionItem( getString(R.string.settings_profile_remove_text), getString(R.string.settings_profile_remove_subtext), - new IconicsDrawable(activity) - .icon(SzkolnyFont.Icon.szf_delete_empty_outline) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) + icon(SzkolnyFont.Icon.szf_delete_empty_outline, iconSizeDp, iconColor) ) .setOnClickAction(() -> { new ProfileRemoveDialog(activity, app.getProfile().getId(), app.getProfile().getName(), false); @@ -269,10 +265,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { new MaterialAboutSwitchItem.Builder() .text(R.string.settings_profile_sync_text) .subText(R.string.settings_profile_sync_subtext) - .icon(new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon.cmd_account_convert) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor))) + .icon(icon(CommunityMaterial.Icon.cmd_account_convert, iconSizeDp, iconColor)) .setChecked(app.getProfile().getSyncEnabled()) .setOnCheckedChanged(((item, isChecked) -> { app.getProfile().setSyncEnabled(isChecked); @@ -302,10 +295,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { new MaterialAboutSwitchItem.Builder() .text(R.string.settings_theme_snowfall_text) .subText(R.string.settings_theme_snowfall_subtext) - .icon(new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon2.cmd_snowflake) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor))) + .icon(icon(CommunityMaterial.Icon2.cmd_snowflake, iconSizeDp, iconColor)) .setChecked(app.getConfig().getUi().getSnowfall()) .setOnCheckedChanged((item, isChecked) -> { app.getConfig().getUi().setSnowfall(isChecked); @@ -320,10 +310,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { new MaterialAboutActionItem( getString(R.string.settings_theme_theme_text), Themes.INSTANCE.getThemeName(activity), - new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon2.cmd_palette_outline) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) + icon(CommunityMaterial.Icon2.cmd_palette_outline, iconSizeDp, iconColor) ) .setOnClickAction(() -> { new MaterialDialog.Builder(activity) @@ -345,10 +332,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { new MaterialAboutSwitchItem.Builder() .text(R.string.settings_theme_mini_drawer_text) .subText(R.string.settings_theme_mini_drawer_subtext) - .icon(new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon.cmd_dots_vertical) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor))) + .icon(icon(CommunityMaterial.Icon.cmd_dots_vertical, iconSizeDp, iconColor)) .setChecked(app.getConfig().getUi().getMiniMenuVisible()) .setOnCheckedChanged((item, isChecked) -> { // 0,1 1 @@ -370,10 +354,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { new MaterialAboutActionItem( getString(R.string.settings_theme_mini_drawer_buttons_text), null, - new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon.cmd_format_list_checks) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) + icon(CommunityMaterial.Icon.cmd_format_list_checks, iconSizeDp, iconColor) ) .setOnClickAction(() -> { List buttonIds = new ArrayList<>(); @@ -434,10 +415,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { new MaterialAboutActionItem( getString(R.string.settings_theme_drawer_header_text), null, - new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon2.cmd_image_outline) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) + icon(CommunityMaterial.Icon2.cmd_image_outline, iconSizeDp, iconColor) ) .setOnClickAction(() -> { if (app.getConfig().getUi().getHeaderBackground() != null) { @@ -468,10 +446,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { new MaterialAboutActionItem( getString(R.string.settings_theme_app_background_text), getString(R.string.settings_theme_app_background_subtext), - new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon2.cmd_image_filter_hdr) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) + icon(CommunityMaterial.Icon2.cmd_image_filter_hdr, iconSizeDp, iconColor) ) .setOnClickAction(() -> { if (app.getConfig().getUi().getAppBackground() != null) { @@ -497,10 +472,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { items.add( new MaterialAboutSwitchItem.Builder( ) .text(R.string.settings_theme_open_drawer_on_back_pressed_text) - .icon(new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon2.cmd_menu_open) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor))) + .icon(icon(CommunityMaterial.Icon2.cmd_menu_open, iconSizeDp, iconColor)) .setChecked(app.getConfig().getUi().getOpenDrawerOnBackPressed()) .setOnCheckedChanged((item, isChecked) -> { app.getConfig().getUi().setOpenDrawerOnBackPressed(isChecked); @@ -549,10 +521,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { return new MaterialAboutSwitchItem.Builder() .text(R.string.settings_sync_wifi_text) .subText(R.string.settings_sync_wifi_subtext) - .icon(new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon2.cmd_wifi_strength_2) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor))) + .icon(icon(CommunityMaterial.Icon2.cmd_wifi_strength_2, iconSizeDp, iconColor)) .setChecked(app.getConfig().getSync().getOnlyWifi()) .setOnCheckedChanged((item, isChecked) -> { app.getConfig().getSync().setOnlyWifi(isChecked); @@ -570,10 +539,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { syncCardIntervalItem = new MaterialAboutActionSwitchItem.Builder() .text(R.string.settings_sync_sync_interval_text) .subText(R.string.settings_sync_sync_interval_subtext_disabled) - .icon(new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon.cmd_download_outline) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor))) + .icon(icon(CommunityMaterial.Icon.cmd_download_outline, iconSizeDp, iconColor)) .build(); syncCardIntervalItem.setSubTextChecked(getSyncCardIntervalSubText()); syncCardIntervalItem.setChecked(app.getConfig().getSync().getEnabled()); @@ -644,10 +610,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { new MaterialAboutSwitchItem( "Cisza na lekcjach", "Nie odtwarzaj dźwięku powiadomień podczas lekcji", - new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon2.cmd_volume_off) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) + icon(CommunityMaterial.Icon2.cmd_volume_off, iconSizeDp, iconColor) ) .setChecked(app.appConfig.quietDuringLessons) .setOnChangeAction((isChecked) -> { @@ -661,10 +624,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { syncCardQuietHoursItem = new MaterialAboutActionSwitchItem.Builder() .text(R.string.settings_sync_quiet_hours_text) .subText(R.string.settings_sync_quiet_hours_subtext_disabled) - .icon(new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon.cmd_bell_sleep_outline) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor))) + .icon(icon(CommunityMaterial.Icon.cmd_bell_sleep_outline, iconSizeDp, iconColor)) .build(); syncCardQuietHoursItem.setChecked(app.getConfig().getSync().getQuietHoursEnabled()); syncCardQuietHoursItem.setSubTextChecked(getSyncCardQuietHoursSubText()); @@ -721,10 +681,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { new MaterialAboutActionItem( getString(R.string.settings_sync_web_push_text), getString(R.string.settings_sync_web_push_subtext), - new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon2.cmd_laptop) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) + icon(CommunityMaterial.Icon2.cmd_laptop, iconSizeDp, iconColor) ) .setOnClickAction(() -> { activity.loadTarget(MainActivity.TARGET_WEB_PUSH, null); @@ -739,10 +696,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { new MaterialAboutActionItem( "Dźwięk powiadomień", "Szkolny.eu", - new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon2.cmd_volume_high) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) + icon(CommunityMaterial.Icon2.cmd_volume_high, iconSizeDp, iconColor) ) .setOnClickAction(() -> { @@ -752,10 +706,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { items.add( new MaterialAboutSwitchItem.Builder() .text(R.string.settings_sync_updates_text) - .icon(new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon.cmd_cellphone_arrow_down) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor))) + .icon(icon(CommunityMaterial.Icon.cmd_cellphone_arrow_down, iconSizeDp, iconColor)) .setChecked(app.getConfig().getSync().getNotifyAboutUpdates()) .setOnCheckedChanged((item, isChecked) -> { app.getConfig().getSync().setNotifyAboutUpdates(isChecked); @@ -770,10 +721,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { new MaterialAboutActionItem( getString(R.string.settings_sync_notifications_settings_text), getString(R.string.settings_sync_notifications_settings_subtext), - new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon2.cmd_settings_outline) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) + icon(CommunityMaterial.Icon2.cmd_settings_outline, iconSizeDp, iconColor) ) .setOnClickAction(() -> { String channel = app.getNotificationChannelsManager().getData().getKey(); @@ -846,10 +794,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { return new MaterialAboutSwitchItem.Builder() .text(R.string.settings_register_shared_events_text) .subText(R.string.settings_register_shared_events_subtext) - .icon(new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon2.cmd_share_outline) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor))) + .icon(icon(CommunityMaterial.Icon2.cmd_share_outline, iconSizeDp, iconColor)) .setChecked(app.getProfile().getEnableSharedEvents()) .setOnCheckedChanged((item, isChecked) -> { app.getProfile().setEnableSharedEvents(isChecked); @@ -877,28 +822,19 @@ public class SettingsNewFragment extends MaterialAboutFragment { items.add(new MaterialAboutActionItem( getString(R.string.menu_grades_config), null, - new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon2.cmd_numeric_5_box_outline) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) + icon(CommunityMaterial.Icon2.cmd_numeric_5_box_outline, iconSizeDp, iconColor) ).setOnClickAction(() -> new GradesConfigDialog(activity, false, null, null))); items.add(new MaterialAboutActionItem( getString(R.string.menu_attendance_config), null, - new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon.cmd_calendar_remove_outline) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) + icon(CommunityMaterial.Icon.cmd_calendar_remove_outline, iconSizeDp, iconColor) ).setOnClickAction(() -> new AttendanceConfigDialog(activity, false, null, null))); registerCardAllowRegistrationItem = new MaterialAboutSwitchItem.Builder() .text(R.string.settings_register_allow_registration_text) .subText(R.string.settings_register_allow_registration_subtext) - .icon(new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon.cmd_account_circle_outline) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor))) + .icon(icon(CommunityMaterial.Icon.cmd_account_circle_outline, iconSizeDp, iconColor)) .build(); registerCardAllowRegistrationItem.setChecked(app.getProfile().getRegistration() == REGISTRATION_ENABLED); registerCardAllowRegistrationItem.setOnCheckedChangedAction((item, isChecked) -> { @@ -955,10 +891,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { registerCardBellSyncItem = new MaterialAboutActionItem( getString(R.string.settings_register_bell_sync_text), getRegisterCardBellSyncSubText(), - new IconicsDrawable(activity) - .icon(SzkolnyFont.Icon.szf_alarm_bell_outline) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor)) + icon(SzkolnyFont.Icon.szf_alarm_bell_outline, iconSizeDp, iconColor) ); registerCardBellSyncItem.setOnClickAction(() -> { new MaterialDialog.Builder(activity) @@ -1025,10 +958,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { new MaterialAboutSwitchItem.Builder() .text(R.string.settings_register_count_in_seconds_text) .subText(R.string.settings_register_count_in_seconds_subtext) - .icon(new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon2.cmd_timer) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor))) + .icon(icon(CommunityMaterial.Icon2.cmd_timer, iconSizeDp, iconColor)) .setChecked(app.getConfig().getTimetable().getCountInSeconds()) .setOnCheckedChanged((item, isChecked) -> { app.getConfig().getTimetable().setCountInSeconds(isChecked); @@ -1041,10 +971,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { items.add( new MaterialAboutSwitchItem.Builder() .text(R.string.settings_register_show_teacher_absences_text) - .icon(new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon.cmd_account_arrow_right_outline) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor))) + .icon(icon(CommunityMaterial.Icon.cmd_account_arrow_right_outline, iconSizeDp, iconColor)) .setChecked(app.getProfile().getStudentData("showTeacherAbsences", true)) .setOnCheckedChanged((item, isChecked) -> { app.getProfile().putStudentData("showTeacherAbsences", isChecked); @@ -1059,10 +986,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { items.add( new MaterialAboutSwitchItem.Builder() .text(R.string.settings_register_hide_sticks_from_old) - .icon(new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon2.cmd_numeric_1_box_outline) - .size(IconicsSize.dp(iconSizeDp)) - .color(IconicsColor.colorInt(iconColor))) + .icon(icon(CommunityMaterial.Icon2.cmd_numeric_1_box_outline, iconSizeDp, iconColor)) .setChecked(app.getConfig().forProfile().getGrades().getHideSticksFromOld()) .setOnCheckedChanged((item, isChecked) -> { app.getConfig().forProfile().getGrades().setHideSticksFromOld(isChecked); @@ -1098,10 +1022,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { pref_about_version = new MaterialAboutActionItem.Builder() .text(R.string.settings_about_version_text) .subText(BuildConfig.VERSION_NAME + ", " + BuildConfig.BUILD_TYPE) - .icon(new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon2.cmd_information_outline) - .color(IconicsColor.colorInt(primaryTextOnPrimaryBg)) - .size(IconicsSize.dp(iconSizeDp))) + .icon(icon(CommunityMaterial.Icon2.cmd_information_outline, iconSizeDp, primaryTextOnPrimaryBg)) .build(); final int[] clickCounter = {0}; pref_about_version.setOnClickAction(() -> { @@ -1120,30 +1041,21 @@ public class SettingsNewFragment extends MaterialAboutFragment { items.add(new MaterialAboutActionItem.Builder() .text(R.string.settings_about_privacy_policy_text) - .icon(new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon2.cmd_shield_outline) - .color(IconicsColor.colorInt(primaryTextOnPrimaryBg)) - .size(IconicsSize.dp(iconSizeDp))) + .icon(icon(CommunityMaterial.Icon2.cmd_shield_outline, iconSizeDp, primaryTextOnPrimaryBg)) .setOnClickAction(ConvenienceBuilder.createWebsiteOnClickAction(activity, Uri.parse("https://szkolny.eu/privacy-policy"))) .build()); items.add(new MaterialAboutActionItem.Builder() .text(R.string.settings_about_discord_text) .subText(R.string.settings_about_discord_subtext) - .icon(new IconicsDrawable(activity) - .icon(SzkolnyFont.Icon.szf_discord_outline) - .color(IconicsColor.colorInt(primaryTextOnPrimaryBg)) - .size(IconicsSize.dp(iconSizeDp))) + .icon(icon(SzkolnyFont.Icon.szf_discord_outline, iconSizeDp, primaryTextOnPrimaryBg)) .setOnClickAction(ConvenienceBuilder.createWebsiteOnClickAction(activity, Uri.parse("https://szkolny.eu/discord"))) .build()); items.add(new MaterialAboutActionItem.Builder() .text(R.string.settings_about_language_text) .subText(R.string.settings_about_language_subtext) - .icon(new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon2.cmd_translate) - .color(IconicsColor.colorInt(primaryTextOnPrimaryBg)) - .size(IconicsSize.dp(iconSizeDp))) + .icon(icon(CommunityMaterial.Icon2.cmd_translate, iconSizeDp, primaryTextOnPrimaryBg)) .setOnClickAction(() -> { new MaterialDialog.Builder(activity) .title(getString(R.string.settings_about_language_dialog_title)) @@ -1178,10 +1090,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { items.add(new MaterialAboutActionItem.Builder() .text(R.string.settings_about_update_text) .subText(R.string.settings_about_update_subtext) - .icon(new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon2.cmd_update) - .color(IconicsColor.colorInt(primaryTextOnPrimaryBg)) - .size(IconicsSize.dp(iconSizeDp))) + .icon(icon(CommunityMaterial.Icon2.cmd_update, iconSizeDp, primaryTextOnPrimaryBg)) .setOnClickAction(() -> { //open browser or intent here NetworkUtils net = new NetworkUtils(app); @@ -1201,19 +1110,13 @@ public class SettingsNewFragment extends MaterialAboutFragment { items.add(new MaterialAboutActionItem.Builder() .text(R.string.settings_about_changelog_text) - .icon(new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon2.cmd_radar) - .color(IconicsColor.colorInt(primaryTextOnPrimaryBg)) - .size(IconicsSize.dp(iconSizeDp))) + .icon(icon(CommunityMaterial.Icon2.cmd_radar, iconSizeDp, primaryTextOnPrimaryBg)) .setOnClickAction(() -> new ChangelogDialog(activity, null, null)) .build()); items.add(new MaterialAboutActionItem.Builder() .text(R.string.settings_about_licenses_text) - .icon(new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon.cmd_code_braces) - .color(IconicsColor.colorInt(primaryTextOnPrimaryBg)) - .size(IconicsSize.dp(iconSizeDp))) + .icon(icon(CommunityMaterial.Icon.cmd_code_braces, iconSizeDp, primaryTextOnPrimaryBg)) .setOnClickAction(() -> { Intent intent = new Intent(activity, SettingsLicenseActivity.class); startActivity(intent); @@ -1222,10 +1125,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { /*items.add(new MaterialAboutActionItem.Builder() .text(R.string.settings_about_intro_text) - .icon(new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon2.cmd_projector_screen) - .color(IconicsColor.colorInt(iconColor)) - .size(IconicsSize.dp(iconSizeDp))) + .icon(icon(CommunityMaterial.Icon2.cmd_projector_screen, iconSizeDp, iconColor)) .setOnClickAction(() -> { if (tryingToDevMode[0]) { if (getParentFragment() instanceof SettingsGeneralFragment) { @@ -1246,10 +1146,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { items.add(new MaterialAboutActionItem.Builder() .text(R.string.settings_about_crash_text) .subText(R.string.settings_about_crash_subtext) - .icon(new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon.cmd_bug_outline) - .color(IconicsColor.colorInt(primaryTextOnPrimaryBg)) - .size(IconicsSize.dp(iconSizeDp))) + .icon(icon(CommunityMaterial.Icon.cmd_bug_outline, iconSizeDp, primaryTextOnPrimaryBg)) .setOnClickAction(() -> { throw new RuntimeException("MANUAL CRASH"); }) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/timetable/TimetableFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/timetable/TimetableFragment.kt index 52441e25..2e3695cc 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/timetable/TimetableFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/timetable/TimetableFragment.kt @@ -18,8 +18,8 @@ import androidx.fragment.app.Fragment import androidx.viewpager.widget.ViewPager import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial.Icon2 -import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont import com.wdullaer.materialdatetimepicker.date.DatePickerDialog +import eu.szkolny.font.SzkolnyFont import kotlinx.coroutines.* import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.MainActivity diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/AttachmentAdapter.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/AttachmentAdapter.kt index 1975f39e..99abba4d 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/AttachmentAdapter.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/AttachmentAdapter.kt @@ -11,11 +11,10 @@ import androidx.core.view.isVisible import androidx.recyclerview.widget.RecyclerView import com.google.android.material.chip.Chip import com.mikepenz.iconics.IconicsDrawable -import com.mikepenz.iconics.typeface.IIcon import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial -import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont import com.mikepenz.iconics.utils.paddingDp import com.mikepenz.iconics.utils.sizeDp +import eu.szkolny.font.SzkolnyFont import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job @@ -60,7 +59,7 @@ class AttachmentAdapter( val fileName = item.name.substringBefore(":http") // create an icon for the attachment - val icon: IIcon = when (Utils.getExtensionFromFileName(fileName)) { + val attachmentIcon = when (Utils.getExtensionFromFileName(fileName)) { "doc", "docx", "odt", "rtf" -> SzkolnyFont.Icon.szf_file_word_outline "xls", "xlsx", "ods" -> SzkolnyFont.Icon.szf_file_excel_outline "ppt", "pptx", "odp" -> SzkolnyFont.Icon.szf_file_powerpoint_outline @@ -82,15 +81,17 @@ class AttachmentAdapter( } ?: fileName } - b.chip.chipIcon = IconicsDrawable(context) - .icon(icon) - .colorAttr(context, R.attr.colorOnSurface) - .sizeDp(24) - .paddingDp(2) - b.chip.closeIcon = IconicsDrawable(context) - .icon(CommunityMaterial.Icon.cmd_check) - .colorAttr(context, R.attr.colorOnSurface) - .sizeDp(18) + b.chip.chipIcon = IconicsDrawable(context).apply { + icon = attachmentIcon + colorAttr(context, R.attr.colorSurface) + sizeDp = 24 + paddingDp = 2 + } + b.chip.closeIcon = IconicsDrawable(context).apply { + icon = CommunityMaterial.Icon.cmd_check + colorAttr(context, R.attr.colorOnSurface) + sizeDp = 18 + } b.chip.isCloseIconVisible = item.isDownloaded && !item.isDownloading // prevent progress bar flickering diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/notifications/WidgetNotificationsProvider.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/notifications/WidgetNotificationsProvider.kt index aec64aef..3832b6c7 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/notifications/WidgetNotificationsProvider.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/notifications/WidgetNotificationsProvider.kt @@ -48,10 +48,10 @@ class WidgetNotificationsProvider : AppWidgetProvider() { views.setImageViewBitmap( R.id.widgetNotificationsSync, - IconicsDrawable(context, CommunityMaterial.Icon.cmd_download_outline) - .colorInt(Color.WHITE) - .sizeDp(iconSize) - .toBitmap() + IconicsDrawable(context, CommunityMaterial.Icon.cmd_download_outline).apply { + colorInt = Color.WHITE + sizeDp = iconSize + }.toBitmap() ) views.setViewVisibility(R.id.widgetNotificationsLoading, View.GONE) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/timetable/WidgetTimetableFactory.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/timetable/WidgetTimetableFactory.java index 6f81bf2c..8a351b1f 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/timetable/WidgetTimetableFactory.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/timetable/WidgetTimetableFactory.java @@ -24,13 +24,14 @@ import android.widget.RemoteViewsService; import androidx.annotation.DrawableRes; -import com.mikepenz.iconics.IconicsColor; import com.mikepenz.iconics.IconicsDrawable; -import com.mikepenz.iconics.IconicsSize; import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial; +import com.mikepenz.iconics.utils.IconicsConvertersKt; +import com.mikepenz.iconics.utils.IconicsDrawableExtensionsKt; import java.util.List; +import kotlin.Unit; import pl.szczodrzynski.edziennik.R; import pl.szczodrzynski.edziennik.utils.models.Date; import pl.szczodrzynski.edziennik.utils.models.ItemWidgetTimetableModel; @@ -126,6 +127,15 @@ public class WidgetTimetableFactory implements RemoteViewsService.RemoteViewsFac return resultBitmap; } + private Bitmap homeIconBitmap() { + return new IconicsDrawable(context).apply((drawable) -> { + IconicsConvertersKt.setColorRes(drawable, R.color.md_red_500); + IconicsConvertersKt.setSizeDp(drawable, 10); + IconicsDrawableExtensionsKt.icon(drawable, CommunityMaterial.Icon2.cmd_home); + return Unit.INSTANCE; + }).toBitmap(); + } + @Override public RemoteViews getViewAt(int i) { RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.row_widget_timetable_item); @@ -270,19 +280,19 @@ public class WidgetTimetableFactory implements RemoteViewsService.RemoteViewsFac if (lesson.eventColors.size() >= 1) { views.setViewVisibility(R.id.widgetTimetableEvent1, View.VISIBLE); if (lesson.eventColors.get(0) == -1) - views.setBitmap(R.id.widgetTimetableEvent1, "setImageBitmap", new IconicsDrawable(context).color(IconicsColor.colorRes(R.color.md_red_500)).size(IconicsSize.dp(10)).icon(CommunityMaterial.Icon2.cmd_home).toBitmap()); + views.setBitmap(R.id.widgetTimetableEvent1, "setImageBitmap", homeIconBitmap()); else views.setBitmap(R.id.widgetTimetableEvent1, "setImageBitmap", getColoredBitmap(context, R.drawable.event_color_circle, lesson.eventColors.get(0), eventIndicatorSize, eventIndicatorSize)); if (lesson.eventColors.size() >= 2) { views.setViewVisibility(R.id.widgetTimetableEvent2, View.VISIBLE); if (lesson.eventColors.get(1) == -1) - views.setBitmap(R.id.widgetTimetableEvent2, "setImageBitmap", new IconicsDrawable(context).color(IconicsColor.colorRes(R.color.md_red_500)).size(IconicsSize.dp(10)).icon(CommunityMaterial.Icon2.cmd_home).toBitmap()); + views.setBitmap(R.id.widgetTimetableEvent2, "setImageBitmap", homeIconBitmap()); else views.setBitmap(R.id.widgetTimetableEvent2, "setImageBitmap", getColoredBitmap(context, R.drawable.event_color_circle, lesson.eventColors.get(1), eventIndicatorSize, eventIndicatorSize)); if (lesson.eventColors.size() >= 3) { views.setViewVisibility(R.id.widgetTimetableEvent3, View.VISIBLE); if (lesson.eventColors.get(2) == -1) - views.setBitmap(R.id.widgetTimetableEvent3, "setImageBitmap", new IconicsDrawable(context).color(IconicsColor.colorRes(R.color.md_red_500)).size(IconicsSize.dp(10)).icon(CommunityMaterial.Icon2.cmd_home).toBitmap()); + views.setBitmap(R.id.widgetTimetableEvent3, "setImageBitmap", homeIconBitmap()); else views.setBitmap(R.id.widgetTimetableEvent3, "setImageBitmap", getColoredBitmap(context, R.drawable.event_color_circle, lesson.eventColors.get(2), eventIndicatorSize, eventIndicatorSize)); } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/timetable/WidgetTimetableProvider.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/timetable/WidgetTimetableProvider.kt index bc284ba2..07db9ea2 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/timetable/WidgetTimetableProvider.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/timetable/WidgetTimetableProvider.kt @@ -115,13 +115,21 @@ class WidgetTimetableProvider : AppWidgetProvider() { views.setOnClickPendingIntent(R.id.widgetTimetableSync, getPendingSelfIntent(context, ACTION_SYNC_DATA)) - views.setImageViewBitmap(R.id.widgetTimetableRefresh, IconicsDrawable(context, CommunityMaterial.Icon2.cmd_refresh) - .colorInt(Color.WHITE) - .sizeDp(if (config.bigStyle) 24 else 16).toBitmap()) + views.setImageViewBitmap( + R.id.widgetTimetableRefresh, + IconicsDrawable(context, CommunityMaterial.Icon2.cmd_refresh).apply { + colorInt = Color.WHITE + sizeDp = if (config.bigStyle) 24 else 16 + }.toBitmap() + ) - views.setImageViewBitmap(R.id.widgetTimetableSync, IconicsDrawable(context, CommunityMaterial.Icon.cmd_download_outline) - .colorInt(Color.WHITE) - .sizeDp(if (config.bigStyle) 24 else 16).toBitmap()) + views.setImageViewBitmap( + R.id.widgetTimetableSync, + IconicsDrawable(context, CommunityMaterial.Icon.cmd_download_outline).apply { + colorInt = Color.WHITE + sizeDp = if (config.bigStyle) 24 else 16 + }.toBitmap() + ) prepareAppWidget(app, appWidgetId, views, config, bellSyncDiffMillis) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/SwipeRefreshLayoutNoIndicator.java b/app/src/main/java/pl/szczodrzynski/edziennik/utils/SwipeRefreshLayoutNoIndicator.java new file mode 100644 index 00000000..75192eec --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/SwipeRefreshLayoutNoIndicator.java @@ -0,0 +1,208 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package pl.szczodrzynski.edziennik.utils; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +/** + * The SwipeRefreshLayout should be used whenever the user can refresh the + * contents of a view via a vertical swipe gesture. The activity that + * instantiates this view should add an OnRefreshListener to be notified + * whenever the swipe to refresh gesture is completed. The SwipeRefreshLayout + * will notify the listener each and every time the gesture is completed again; + * the listener is responsible for correctly determining when to actually + * initiate a refresh of its content. If the listener determines there should + * not be a refresh, it must call setRefreshing(false) to cancel any visual + * indication of a refresh. If an activity wishes to show just the progress + * animation, it should call setRefreshing(true). To disable the gesture and + * progress animation, call setEnabled(false) on the view. + *

+ * This layout should be made the parent of the view that will be refreshed as a + * result of the gesture and can only support one direct child. This view will + * also be made the target of the gesture and will be forced to match both the + * width and the height supplied in this layout. The SwipeRefreshLayout does not + * provide accessibility events; instead, a menu item must be provided to allow + * refresh of the content wherever this gesture is used. + *

+ */ +public class SwipeRefreshLayoutNoIndicator extends SwipeRefreshLayout { + + private SwipeRefreshLayoutNoTouch parent; + + @Override + public void setEnabled(boolean enabled) { + if (parent == null) + return; + parent.setEnabled(enabled); + super.setEnabled(enabled); + } + + public void setParent(SwipeRefreshLayoutNoTouch parent) { + this.parent = parent; + } + + /** + * Simple constructor to use when creating a SwipeRefreshLayout from code. + * + * @param context + */ + public SwipeRefreshLayoutNoIndicator(@NonNull Context context) { + this(context, null); + } + + /** + * Constructor that is called when inflating SwipeRefreshLayout from XML. + * + * @param context + * @param attrs + */ + public SwipeRefreshLayoutNoIndicator(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + ev.setSource(0x10000000); + boolean parentConsumed = parent.onInterceptTouchEvent(ev); + boolean superConsumed = super.onInterceptTouchEvent(ev); + return parentConsumed && superConsumed; + /*if (super.onInterceptTouchEvent(ev)) + return parent.onInterceptTouchEvent(ev); + return false;*/ + } + + @Override + public void requestDisallowInterceptTouchEvent(boolean b) { + parent.requestDisallowInterceptTouchEvent(b); + } + + // NestedScrollingParent + + @Override + public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) { + parent.onStartNestedScroll(child, target, nestedScrollAxes); + return !parent.isRefreshing() && super.onStartNestedScroll(child, target, nestedScrollAxes); + } + + @Override + public void onNestedScrollAccepted(View child, View target, int axes) { + parent.onNestedScrollAccepted(child, target, axes); + } + + @Override + public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) { + parent.onNestedPreScroll(target, dx, dy, consumed); + } + + @Override + public int getNestedScrollAxes() { + return parent.getNestedScrollAxes(); + } + + @Override + public void onStopNestedScroll(View target) { + parent.onStopNestedScroll(target); + } + + @Override + public void onNestedScroll(final View target, final int dxConsumed, final int dyConsumed, + final int dxUnconsumed, final int dyUnconsumed) { + parent.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed); + } + + // NestedScrollingChild + + @Override + public void setNestedScrollingEnabled(boolean enabled) { + if (parent == null) + return; + //parent.setNestedScrollingEnabled(enabled); + super.setNestedScrollingEnabled(enabled); + } + + @Override + public boolean isNestedScrollingEnabled() { + return parent.isNestedScrollingEnabled(); + } + + @Override + public boolean startNestedScroll(int axes) { + return parent.startNestedScroll(axes); + } + + @Override + public void stopNestedScroll() { + parent.stopNestedScroll(); + } + + @Override + public boolean hasNestedScrollingParent() { + return parent.hasNestedScrollingParent(); + } + + @Override + public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, + int dyUnconsumed, int[] offsetInWindow) { + return super.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow); + } + + @Override + public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) { + return super.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow); + } + + @Override + public boolean onNestedPreFling(View target, float velocityX, + float velocityY) { + return parent.onNestedPreFling(target, velocityX, velocityY); + } + + @Override + public boolean onNestedFling(View target, float velocityX, float velocityY, + boolean consumed) { + return parent.onNestedFling(target, velocityX, velocityY, consumed); + } + + @Override + public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { + return parent.dispatchNestedFling(velocityX, velocityY, consumed); + } + + @Override + public boolean dispatchNestedPreFling(float velocityX, float velocityY) { + return parent.dispatchNestedPreFling(velocityX, velocityY); + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + ev.setSource(0x10000000); + /*boolean consumed = super.onTouchEvent(ev); + if (consumed) { + return false; + }*/ + return parent.onTouchEvent(ev); + } + + +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/SwipeRefreshLayoutNoTouch.java b/app/src/main/java/pl/szczodrzynski/edziennik/utils/SwipeRefreshLayoutNoTouch.java new file mode 100644 index 00000000..0b2daf51 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/SwipeRefreshLayoutNoTouch.java @@ -0,0 +1,51 @@ +package pl.szczodrzynski.edziennik.utils; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + + +public class SwipeRefreshLayoutNoTouch extends SwipeRefreshLayout { + public SwipeRefreshLayoutNoTouch(@NonNull Context context) { + super(context); + } + + public SwipeRefreshLayoutNoTouch(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + @Override + public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) { + return false; + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + if (ev.getSource() == 0x10000000) { + // forward the event to super + return super.onInterceptTouchEvent(ev); + } + // discard all the other events + return false; + + /*if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) + return false; + super.onInterceptTouchEvent(ev); + return false;*/ + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + if (ev.getSource() == 0x10000000) { + // forward the event to super + return super.onTouchEvent(ev); + } + // discard all the other events + return false; + } +} diff --git a/build.gradle b/build.gradle index c0fb9910..fd64a16a 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ buildscript { materialdialogs : "0.9.6.0", materialdrawer : "817e45765c367034b03046aaea6e95eeabcb40e9", - iconics : "4.0.1", + iconics : "5.2.8", font_cmd : "3.5.95.1-kotlin", navlib : "28cdab341470dffa5f331379fe9702482681d7de", diff --git a/settings.gradle b/settings.gradle index 680b7d04..a1b55163 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,7 +3,7 @@ include ':wear' include ':codegen' include ':annotation' rootProject.name='Szkolny.eu' -include ':app', ':szkolny-font' +include ':app' /* include ':Navigation' project(':Navigation').projectDir = new File(settingsDir, '../Navigation/navlib')*/ diff --git a/szkolny-font/build.gradle b/szkolny-font/build.gradle deleted file mode 100644 index 70d20b0d..00000000 --- a/szkolny-font/build.gradle +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2019 Mike Penz - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -apply plugin: 'com.android.library' - -apply plugin: 'kotlin-android' - -android { - compileSdkVersion setup.compileSdk - - defaultConfig { - minSdkVersion setup.minSdk - targetSdkVersion setup.targetSdk - consumerProguardFiles 'consumer-proguard-rules.pro' - versionCode 11 - versionName "1.1" - } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - debugMinify { - debuggable = true - minifyEnabled = true - proguardFiles 'proguard-android.txt' - } - } -} -if (project.hasProperty('pushall') || project.hasProperty('SzkolnyFontonly')) { - apply from: '../gradle-mvn-push.gradle' -} - -dependencies { - implementation "com.mikepenz:iconics-core:${versions.iconics}" - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${versions.kotlin}" -} diff --git a/szkolny-font/consumer-proguard-rules.pro b/szkolny-font/consumer-proguard-rules.pro deleted file mode 100644 index 61d1083d..00000000 --- a/szkolny-font/consumer-proguard-rules.pro +++ /dev/null @@ -1 +0,0 @@ --keep class com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont { *; } diff --git a/szkolny-font/gradle.properties b/szkolny-font/gradle.properties deleted file mode 100644 index 82ee377a..00000000 --- a/szkolny-font/gradle.properties +++ /dev/null @@ -1,40 +0,0 @@ -# -# Copyright 2014 Mike Penz -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Project-wide Gradle settings. - -# IDE (e.g. Android Studio) users: -# Settings specified in this file will override any Gradle settings -# configured through the IDE. - -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html - -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -# Default value: -Xmx10248m -XX:MaxPermSize=256m -# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 - -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true -VERSION_NAME=1.0 -VERSION_CODE=1 - -POM_NAME=Android-Iconics Szkolny.eu Icon Font Typeface Library -POM_ARTIFACT_ID=szkolny-font-typeface -POM_PACKAGING=aar diff --git a/szkolny-font/src/main/AndroidManifest.xml b/szkolny-font/src/main/AndroidManifest.xml deleted file mode 100644 index e4bf2179..00000000 --- a/szkolny-font/src/main/AndroidManifest.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - diff --git a/szkolny-font/src/main/java/com/mikepenz/iconics/typeface/library/szkolny/font/SzkolnyFont.kt b/szkolny-font/src/main/java/com/mikepenz/iconics/typeface/library/szkolny/font/SzkolnyFont.kt deleted file mode 100644 index 5e23dbd1..00000000 --- a/szkolny-font/src/main/java/com/mikepenz/iconics/typeface/library/szkolny/font/SzkolnyFont.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2019 Mike Penz - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.mikepenz.iconics.typeface.library.szkolny.font - -import com.mikepenz.iconics.typeface.IIcon -import com.mikepenz.iconics.typeface.ITypeface -import com.mikepenz.iconics.typeface.library.szkolny.R -import java.util.* - -@Suppress("EnumEntryName") -object SzkolnyFont : ITypeface { - - override val fontRes: Int - get() = R.font.szkolny_font_font_v1_1 - - override val characters: Map by lazy { - Icon.values().associate { it.name to it.character } - } - - override val mappingPrefix: String - get() = "szf" - - override val fontName: String - get() = "Szkolny Font" - - override val version: String - get() = "1.1" - - override val iconCount: Int - get() = characters.size - - override val icons: List - get() = characters.keys.toCollection(LinkedList()) - - override val author: String - get() = "Kuba" - - override val url: String - get() = "" - - override val description: String - get() = "" - - override val license: String - get() = "" - - override val licenseUrl: String - get() = "" - - override fun getIcon(key: String): IIcon = Icon.valueOf(key) - - enum class Icon constructor(override val character: Char) : IIcon { - szf_alarm_bell_outline('\ue800'), - szf_calendar_plus_outline('\ue801'), - szf_calendar_today_outline('\ue802'), - szf_clipboard_list_outline('\ue803'), - szf_delete_empty_outline('\ue804'), - szf_discord_outline('\ue805'), - szf_file_code_outline('\ue806'), - szf_file_excel_outline('\ue807'), - szf_file_image_outline('\ue808'), - szf_file_music_outline('\ue809'), - szf_file_pdf_outline('\ue80a'), - szf_file_percent_outline('\ue80b'), - szf_file_powerpoint_outline('\ue80c'), - szf_file_video_outline('\ue80d'), - szf_file_word_outline('\ue80e'), - szf_message_processing_outline('\ue80f'), - szf_notebook_outline('\ue810'), - szf_zip_box_outline('\ue811'); - - override val typeface: ITypeface by lazy { SzkolnyFont } - } -} \ No newline at end of file diff --git a/szkolny-font/src/main/res/font/szkolny_font_font_v1_1.ttf b/szkolny-font/src/main/res/font/szkolny_font_font_v1_1.ttf deleted file mode 100644 index 33ad627f3fa830143956fc4b3e8e5d0bb8abaaf2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11232 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 diff --git a/szkolny-font/src/main/res/values/font_addon.xml b/szkolny-font/src/main/res/values/font_addon.xml deleted file mode 100644 index 3ea04e70..00000000 --- a/szkolny-font/src/main/res/values/font_addon.xml +++ /dev/null @@ -1,2 +0,0 @@ - - From ea3598bb6d9a6a6263629207458c90e377976d3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 21 Mar 2021 18:21:14 +0100 Subject: [PATCH 010/113] [Gradle] Extract selective-dao dependency. --- annotation/.gitignore | 1 - annotation/build.gradle | 29 -- .../edziennik/annotation/SelectiveDao.kt | 14 - .../edziennik/annotation/UpdateSelective.kt | 13 - app/build.gradle | 5 +- .../edziennik/data/db/dao/AnnouncementDao.kt | 4 +- .../edziennik/data/db/dao/AttendanceDao.kt | 4 +- .../edziennik/data/db/dao/EventDao.kt | 4 +- .../edziennik/data/db/dao/GradeDao.kt | 4 +- .../edziennik/data/db/dao/LuckyNumberDao.kt | 4 +- .../edziennik/data/db/dao/MessageDao.kt | 4 +- .../edziennik/data/db/dao/NoticeDao.kt | 4 +- .../data/db/dao/TeacherAbsenceDao.kt | 4 +- .../edziennik/data/db/dao/TimetableDao.kt | 4 +- codegen/.gitignore | 1 - codegen/build.gradle | 39 -- .../edziennik/codegen/FileGenerator.kt | 342 ------------------ settings.gradle | 2 - 18 files changed, 20 insertions(+), 462 deletions(-) delete mode 100644 annotation/.gitignore delete mode 100644 annotation/build.gradle delete mode 100644 annotation/src/main/java/pl/szczodrzynski/edziennik/annotation/SelectiveDao.kt delete mode 100644 annotation/src/main/java/pl/szczodrzynski/edziennik/annotation/UpdateSelective.kt delete mode 100644 codegen/.gitignore delete mode 100644 codegen/build.gradle delete mode 100644 codegen/src/main/java/pl/szczodrzynski/edziennik/codegen/FileGenerator.kt diff --git a/annotation/.gitignore b/annotation/.gitignore deleted file mode 100644 index 796b96d1..00000000 --- a/annotation/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/annotation/build.gradle b/annotation/build.gradle deleted file mode 100644 index ee7f6d51..00000000 --- a/annotation/build.gradle +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) Kuba Szczodrzyński 2020-3-28. - */ - -apply plugin: 'java-library' -apply plugin: 'kotlin' -apply plugin: 'kotlin-kapt' - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" -} - -sourceCompatibility = "7" -targetCompatibility = "7" - -repositories { - mavenCentral() -} -compileKotlin { - kotlinOptions { - jvmTarget = "1.8" - } -} -compileTestKotlin { - kotlinOptions { - jvmTarget = "1.8" - } -} diff --git a/annotation/src/main/java/pl/szczodrzynski/edziennik/annotation/SelectiveDao.kt b/annotation/src/main/java/pl/szczodrzynski/edziennik/annotation/SelectiveDao.kt deleted file mode 100644 index d37e5b0a..00000000 --- a/annotation/src/main/java/pl/szczodrzynski/edziennik/annotation/SelectiveDao.kt +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) Kuba Szczodrzyński 2020-3-28. - */ - -package pl.szczodrzynski.edziennik.annotation - -import kotlin.reflect.KClass - -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.SOURCE) -@MustBeDocumented -annotation class SelectiveDao( - val db: KClass<*> -) diff --git a/annotation/src/main/java/pl/szczodrzynski/edziennik/annotation/UpdateSelective.kt b/annotation/src/main/java/pl/szczodrzynski/edziennik/annotation/UpdateSelective.kt deleted file mode 100644 index 224fca1c..00000000 --- a/annotation/src/main/java/pl/szczodrzynski/edziennik/annotation/UpdateSelective.kt +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright (c) Kuba Szczodrzyński 2020-3-28. - */ - -package pl.szczodrzynski.edziennik.annotation - -@Target(AnnotationTarget.FUNCTION) -@Retention(AnnotationRetention.SOURCE) -@MustBeDocumented -annotation class UpdateSelective( - val primaryKeys: Array, - val skippedColumns: Array = [] -) diff --git a/app/build.gradle b/app/build.gradle index 4ad2fc5f..47d1b31b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -167,6 +167,8 @@ dependencies { implementation "eu.szkolny:nachos:0e5dfcaceb" //implementation project(":Navigation") implementation "eu.szkolny:szkolny-font:1dab7d64ed" + implementation "eu.szkolny.selective-dao:annotation:27f8f3f194" + kapt "eu.szkolny.selective-dao:codegen:27f8f3f194" implementation "com.github.ChuckerTeam.Chucker:library:3.0.1" //releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:3.0.1" @@ -195,9 +197,6 @@ dependencies { implementation 'com.github.kuba2k2:NumberSlidingPicker:2921225f76' - implementation project(":annotation") - kapt project(":codegen") - implementation 'com.google.android:flexbox:2.0.1' implementation 'com.qifan.powerpermission:powerpermission:1.3.0' diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AnnouncementDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AnnouncementDao.kt index 67e034c5..88b3ccd1 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AnnouncementDao.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AnnouncementDao.kt @@ -8,9 +8,9 @@ import androidx.room.Dao import androidx.room.Query import androidx.room.RawQuery import androidx.sqlite.db.SupportSQLiteQuery +import eu.szkolny.selectivedao.annotation.SelectiveDao +import eu.szkolny.selectivedao.annotation.UpdateSelective import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.annotation.SelectiveDao -import pl.szczodrzynski.edziennik.annotation.UpdateSelective import pl.szczodrzynski.edziennik.data.db.AppDb import pl.szczodrzynski.edziennik.data.db.entity.Announcement import pl.szczodrzynski.edziennik.data.db.entity.Metadata diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AttendanceDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AttendanceDao.kt index 97513689..3ffdc1b8 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AttendanceDao.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AttendanceDao.kt @@ -8,9 +8,9 @@ import androidx.room.Dao import androidx.room.Query import androidx.room.RawQuery import androidx.sqlite.db.SupportSQLiteQuery +import eu.szkolny.selectivedao.annotation.SelectiveDao +import eu.szkolny.selectivedao.annotation.UpdateSelective import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.annotation.SelectiveDao -import pl.szczodrzynski.edziennik.annotation.UpdateSelective import pl.szczodrzynski.edziennik.data.db.AppDb import pl.szczodrzynski.edziennik.data.db.entity.Attendance import pl.szczodrzynski.edziennik.data.db.entity.Metadata diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/EventDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/EventDao.kt index a532602b..897d53ff 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/EventDao.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/EventDao.kt @@ -10,9 +10,9 @@ import androidx.room.RawQuery import androidx.room.Transaction import androidx.sqlite.db.SimpleSQLiteQuery import androidx.sqlite.db.SupportSQLiteQuery +import eu.szkolny.selectivedao.annotation.SelectiveDao +import eu.szkolny.selectivedao.annotation.UpdateSelective import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.annotation.SelectiveDao -import pl.szczodrzynski.edziennik.annotation.UpdateSelective import pl.szczodrzynski.edziennik.data.db.AppDb import pl.szczodrzynski.edziennik.data.db.entity.Event import pl.szczodrzynski.edziennik.data.db.entity.Metadata diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/GradeDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/GradeDao.kt index 4fcfc721..6254f80b 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/GradeDao.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/GradeDao.kt @@ -9,9 +9,9 @@ import androidx.room.Query import androidx.room.RawQuery import androidx.room.Transaction import androidx.sqlite.db.SupportSQLiteQuery +import eu.szkolny.selectivedao.annotation.SelectiveDao +import eu.szkolny.selectivedao.annotation.UpdateSelective import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.annotation.SelectiveDao -import pl.szczodrzynski.edziennik.annotation.UpdateSelective import pl.szczodrzynski.edziennik.data.db.AppDb import pl.szczodrzynski.edziennik.data.db.entity.Grade import pl.szczodrzynski.edziennik.data.db.entity.Metadata diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/LuckyNumberDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/LuckyNumberDao.kt index ad44c0d3..3c752124 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/LuckyNumberDao.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/LuckyNumberDao.kt @@ -8,9 +8,9 @@ import androidx.room.Dao import androidx.room.Query import androidx.room.RawQuery import androidx.sqlite.db.SupportSQLiteQuery +import eu.szkolny.selectivedao.annotation.SelectiveDao +import eu.szkolny.selectivedao.annotation.UpdateSelective import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.annotation.SelectiveDao -import pl.szczodrzynski.edziennik.annotation.UpdateSelective import pl.szczodrzynski.edziennik.data.db.AppDb import pl.szczodrzynski.edziennik.data.db.entity.LuckyNumber import pl.szczodrzynski.edziennik.data.db.entity.Metadata diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/MessageDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/MessageDao.kt index a0be36ab..51d56854 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/MessageDao.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/MessageDao.kt @@ -8,9 +8,9 @@ import androidx.room.Dao import androidx.room.Query import androidx.room.RawQuery import androidx.sqlite.db.SupportSQLiteQuery +import eu.szkolny.selectivedao.annotation.SelectiveDao +import eu.szkolny.selectivedao.annotation.UpdateSelective import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.annotation.SelectiveDao -import pl.szczodrzynski.edziennik.annotation.UpdateSelective import pl.szczodrzynski.edziennik.data.db.AppDb import pl.szczodrzynski.edziennik.data.db.entity.Message import pl.szczodrzynski.edziennik.data.db.entity.Metadata diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/NoticeDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/NoticeDao.kt index 79bae175..51f3e839 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/NoticeDao.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/NoticeDao.kt @@ -8,9 +8,9 @@ import androidx.room.Dao import androidx.room.Query import androidx.room.RawQuery import androidx.sqlite.db.SupportSQLiteQuery +import eu.szkolny.selectivedao.annotation.SelectiveDao +import eu.szkolny.selectivedao.annotation.UpdateSelective import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.annotation.SelectiveDao -import pl.szczodrzynski.edziennik.annotation.UpdateSelective import pl.szczodrzynski.edziennik.data.db.AppDb import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Notice diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/TeacherAbsenceDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/TeacherAbsenceDao.kt index 1528adf1..f12248b8 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/TeacherAbsenceDao.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/TeacherAbsenceDao.kt @@ -8,9 +8,9 @@ import androidx.room.Dao import androidx.room.Query import androidx.room.RawQuery import androidx.sqlite.db.SupportSQLiteQuery +import eu.szkolny.selectivedao.annotation.SelectiveDao +import eu.szkolny.selectivedao.annotation.UpdateSelective import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.annotation.SelectiveDao -import pl.szczodrzynski.edziennik.annotation.UpdateSelective import pl.szczodrzynski.edziennik.data.db.AppDb import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.TeacherAbsence diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/TimetableDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/TimetableDao.kt index cc236dc6..c7cbee12 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/TimetableDao.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/TimetableDao.kt @@ -8,9 +8,9 @@ import androidx.room.Dao import androidx.room.Query import androidx.room.RawQuery import androidx.sqlite.db.SupportSQLiteQuery +import eu.szkolny.selectivedao.annotation.SelectiveDao +import eu.szkolny.selectivedao.annotation.UpdateSelective import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.annotation.SelectiveDao -import pl.szczodrzynski.edziennik.annotation.UpdateSelective import pl.szczodrzynski.edziennik.data.db.AppDb import pl.szczodrzynski.edziennik.data.db.entity.Lesson import pl.szczodrzynski.edziennik.data.db.entity.Metadata diff --git a/codegen/.gitignore b/codegen/.gitignore deleted file mode 100644 index 796b96d1..00000000 --- a/codegen/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/codegen/build.gradle b/codegen/build.gradle deleted file mode 100644 index e2630bd0..00000000 --- a/codegen/build.gradle +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) Kuba Szczodrzyński 2020-3-28. - */ - -apply plugin: 'java-library' -apply plugin: 'kotlin' -apply plugin: 'kotlin-kapt' - -kapt { - generateStubs = true -} - -sourceSets { - main { - java { - srcDir "${buildDir.absolutePath}/tmp/kapt/main/kotlinGenerated/" - } - } -} - - -dependencies { - kapt project(":annotation") - compileOnly project(':annotation') - implementation fileTree(include: ['*.jar'], dir: 'libs') - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - - // configuration generator for service providers - implementation "com.google.auto.service:auto-service:1.0-rc4" - kapt "com.google.auto.service:auto-service:1.0-rc4" - kapt "androidx.room:room-compiler:${versions.room}" - implementation "androidx.room:room-runtime:${versions.room}" - implementation "com.squareup:kotlinpoet:1.5.0" - implementation "androidx.sqlite:sqlite:2.1.0@aar" - -} - -sourceCompatibility = "7" -targetCompatibility = "7" diff --git a/codegen/src/main/java/pl/szczodrzynski/edziennik/codegen/FileGenerator.kt b/codegen/src/main/java/pl/szczodrzynski/edziennik/codegen/FileGenerator.kt deleted file mode 100644 index 5b5b1f71..00000000 --- a/codegen/src/main/java/pl/szczodrzynski/edziennik/codegen/FileGenerator.kt +++ /dev/null @@ -1,342 +0,0 @@ -/* - * Copyright (c) Kuba Szczodrzyński 2020-3-28. - */ - -package pl.szczodrzynski.edziennik.codegen - -import androidx.room.ColumnInfo -import androidx.room.Entity -import androidx.room.Ignore -import androidx.room.TypeConverters -import com.google.auto.service.AutoService -import com.squareup.kotlinpoet.* -import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy -import pl.szczodrzynski.edziennik.annotation.SelectiveDao -import pl.szczodrzynski.edziennik.annotation.UpdateSelective -import java.io.File -import javax.annotation.processing.* -import javax.lang.model.SourceVersion -import javax.lang.model.element.* -import javax.lang.model.type.* -import javax.lang.model.util.ElementFilter -import javax.tools.Diagnostic -import kotlin.reflect.KClass - -@Suppress("unused") -@AutoService(Processor::class) -@SupportedSourceVersion(SourceVersion.RELEASE_8) -@SupportedOptions(FileGenerator.KAPT_KOTLIN_GENERATED_OPTION_NAME) -class FileGenerator : AbstractProcessor() { - companion object { - const val KAPT_KOTLIN_GENERATED_OPTION_NAME = "kapt.kotlin.generated" - } - - private data class TypeConverter(val dataType: TypeMirror, val converterType: TypeElement, val methodName: Name, val returnType: TypeMirror) - - private inline fun Element.getAnnotationClassValue(f: T.() -> KClass<*>) = try { - getAnnotation(T::class.java).f() - throw Exception("Expected to get a MirroredTypeException") - } catch (e: MirroredTypeException) { - e.typeMirror - } - private inline fun Element.getAnnotationClassValues(f: T.() -> Array>) = try { - getAnnotation(T::class.java).f() - throw Exception("Expected to get a MirroredTypesException") - } catch (e: MirroredTypesException) { - e.typeMirrors - } - - override fun process(set: MutableSet?, roundEnvironment: RoundEnvironment?): Boolean { - roundEnvironment?.getElementsAnnotatedWith(SelectiveDao::class.java)?.forEach { it -> - if (it.kind != ElementKind.CLASS) { - processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, "Can only be applied to classes, element: $it") - return false - } - - val generatedSourcesRoot = processingEnv.options[KAPT_KOTLIN_GENERATED_OPTION_NAME] - if (generatedSourcesRoot?.isEmpty() != false) { - processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, "Can't find the target directory for generated Kotlin files.") - return false - } - - val file = File(generatedSourcesRoot) - file.mkdirs() - - val dao = it as TypeElement - processClass(dao, file) - - //processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, "package = $packageName, className = $className, methodName = $methodName, tableName = $tableName, paramName = $paramName, paramClass = $paramClass") - } - return true - } - - private fun processClass(dao: TypeElement, file: File) { - val daoName = dao.simpleName.toString() - val packageName = processingEnv.elementUtils.getPackageOf(dao).toString() - - val dbType = processingEnv.typeUtils.asElement(dao.getAnnotationClassValue { db }) as TypeElement - val typeConverters = dbType.getAnnotationClassValues { value }.map { - processingEnv.typeUtils.asElement(it) as TypeElement - }.map { type -> - processingEnv.elementUtils.getAllMembers(type).mapNotNull { element -> - if (element is ExecutableElement) { - if (element.returnType.toString() == "java.lang.String" - || element.returnType.toString() == "java.lang.Long" - || element.returnType.toString() == "java.lang.Integer" - || element.returnType.kind.isPrimitive) { - if (element.simpleName.startsWith("to") && element.parameters.isNotEmpty()) - return@mapNotNull TypeConverter(element.parameters.first().asType(), type, element.simpleName, element.returnType) - } - } - null - } - }.flatten() - - //processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, "c = ${typeConverters.joinToString()}") - - val roomDatabase = ClassName("androidx.room", "RoomDatabase") - val selective = TypeSpec.classBuilder("${daoName}Selective") - .primaryConstructor(FunSpec.constructorBuilder() - .addParameter("__db", roomDatabase, KModifier.PRIVATE) - .build()) - .addProperty(PropertySpec.builder("__db", roomDatabase) - .initializer("__db") - .addModifiers(KModifier.PRIVATE) - .build()) - - val usedTypeConverters = mutableSetOf() - - processingEnv.elementUtils.getAllMembers(dao).forEach { element -> - if (element.kind != ElementKind.METHOD) - return@forEach - val method = element as ExecutableElement - val annotation = method.getAnnotation(UpdateSelective::class.java) ?: return@forEach - usedTypeConverters.addAll(processMethod(selective, method, annotation, typeConverters)) - } - - usedTypeConverters.forEach { converter -> - selective.addProperty(PropertySpec.builder("__${converter.converterType.simpleName}", converter.converterType.asType().asTypeName(), KModifier.PRIVATE) - .delegate(CodeBlock.builder() - .beginControlFlow("lazy") - .addStatement("%T()", converter.converterType.asType().asTypeName()) - .endControlFlow() - .build()) - .build()) - } - - FileSpec.builder(packageName, "${daoName}Selective") - .addType(selective.build()) - .build() - .writeTo(file) - } - - private fun VariableElement.name() = getAnnotation(ColumnInfo::class.java)?.name ?: simpleName.toString() - - private fun processMethod(cls: TypeSpec.Builder, method: ExecutableElement, annotation: UpdateSelective, typeConverters: List): List { - val methodName = method.simpleName.toString() - val parameter = method.parameters.first() - val paramName = parameter.simpleName.toString() - val paramTypeElement = processingEnv.typeUtils.asElement(parameter.asType()) as TypeElement - val paramTypeAnnotation = paramTypeElement.getAnnotation(Entity::class.java) - - val tableName = paramTypeAnnotation.tableName - val primaryKeys = annotation.primaryKeys - val skippedColumns = annotation.skippedColumns - - - var members = processingEnv.elementUtils.getAllMembers(paramTypeElement) - val allFields = ElementFilter.fieldsIn(members) - - // check all super classes - var superType = paramTypeElement.superclass - while (superType !is NoType) { - val superTypeElement = processingEnv.typeUtils.asElement(superType) as TypeElement - members = processingEnv.elementUtils.getAllMembers(superTypeElement) - allFields += ElementFilter.fieldsIn(members) - superType = superTypeElement.superclass - } - - allFields.removeAll { skippedColumns.contains(it.name()) } - allFields.removeAll { it.getAnnotation(Ignore::class.java) != null } - allFields.removeAll { field -> field.modifiers.any { it == Modifier.STATIC } } - val allFieldsDistinct = allFields.distinct() - - // dump fields - //processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, allFieldsDistinct.joinToString()) - - val fields = allFieldsDistinct.filterNot { primaryKeys.contains(it.name()) } - val primaryFields = allFieldsDistinct.filter { primaryKeys.contains(it.name()) } - val fieldNames = fields.map { it.name() } - val primaryFieldNames = primaryFields.map { it.name() } - - val fieldNamesQuery = fieldNames.joinToString { "$it = ?" } - val primaryFieldNamesQuery = primaryFieldNames.joinToString(" AND ") { "$it = ?" } - val query = "\"\"\"UPDATE $tableName SET $fieldNamesQuery WHERE $primaryFieldNamesQuery\"\"\"" - - val entityInsertionAdapter = ClassName("androidx.room", "EntityInsertionAdapter") - val supportSQLiteStatement = ClassName("androidx.sqlite.db", "SupportSQLiteStatement") - - val usedTypeConverters = mutableListOf() - - val bind = CodeBlock.builder() - (fields+primaryFields).forEachIndexed { i, field -> - val index = i+1 - val fieldName = field.simpleName.toString() - val name = "${paramName}_$fieldName" - val realName = "${paramName}.$fieldName" - val nullable = field.getAnnotation(org.jetbrains.annotations.Nullable::class.java) != null - - var param = when (field.asType().kind) { - TypeKind.BOOLEAN -> "if ($name) 1L else 0L" - TypeKind.BYTE, - TypeKind.SHORT, - TypeKind.INT -> "$name.toLong()" - TypeKind.CHAR -> "$name.toString()" - TypeKind.FLOAT -> "$name.toDouble()" - else -> when (field.asType().toString()) { - "java.lang.String" -> name - "java.lang.Boolean" -> "if ($name == true) 1L else 0L" - "java.lang.Byte", - "java.lang.Short", - "java.lang.Integer" -> "$name.toLong()" - "java.lang.Long" -> name - "java.lang.Char" -> "$name.toString()" - "java.lang.Float" -> "$name.toDouble()" - "java.lang.Double" -> name - else -> name - } - } - - var isConvert = false - val bindMethod = when (field.asType().kind) { - TypeKind.BOOLEAN -> "bindLong" - TypeKind.BYTE -> "bindLong" - TypeKind.SHORT -> "bindLong" - TypeKind.INT -> "bindLong" - TypeKind.LONG -> "bindLong" - TypeKind.CHAR -> "bindString" - TypeKind.FLOAT -> "bindDouble" - TypeKind.DOUBLE -> "bindDouble" - else -> when (field.asType().toString()) { - "java.lang.String" -> "bindString" - "java.lang.Boolean" -> "bindLong" - "java.lang.Byte" -> "bindLong" - "java.lang.Short" -> "bindLong" - "java.lang.Integer" -> "bindLong" - "java.lang.Long" -> "bindLong" - "java.lang.Char" -> "bindString" - "java.lang.Float" -> "bindDouble" - "java.lang.Double" -> "bindDouble" - else -> { - val converter = typeConverters.firstOrNull { - it.dataType.toString() == field.asType().toString() - } - if (converter != null) { - param = "__${converter.converterType.simpleName}.${converter.methodName}($realName)" - param = when (converter.returnType.toString()) { - "java.lang.Integer", "int", - "java.lang.Short", "short", - "java.lang.Byte", "byte" -> "$param.toLong()" - "java.lang.Boolean", "boolean" -> "if ($param) 1L else 0L" - "java.lang.Char", "char" -> "$param.toString()" - "java.lang.Float", "float" -> "$param.toDouble()" - else -> param - } - isConvert = true - usedTypeConverters += converter - when (converter.returnType.toString()) { - "java.lang.Integer", "int", - "java.lang.Short", "short", - "java.lang.Byte", "byte", - "java.lang.Boolean", "boolean" -> "bindLong" - "java.lang.Char", "char" -> "bindString" - "java.lang.Float", "float" -> "bindDouble" - else -> "bindString" - } - } - else "bind${field.asType()}" - } - } - } - - if (!isConvert) { - bind.addStatement("val $name = $realName") - } - else { - bind.addStatement("val $name = $param") - param = name - } - if (nullable) { - bind.beginControlFlow("if ($name == null)") - .addStatement("stmt.bindNull($index)") - .endControlFlow() - .beginControlFlow("else") - .addStatement("stmt.$bindMethod($index, $param)") - .endControlFlow() - } - else { - bind.addStatement("stmt.$bindMethod($index, $param)") - } - } - - val adapterName = "__insertionAdapterOf$methodName" - val delegate = CodeBlock.builder().add(""" - |lazy { - | object : EntityInsertionAdapter<%T>(__db) { - | override fun createQuery() = $query - | override fun bind(stmt: %T, $paramName: %T) { - |${bind.indent().indent().indent().build()} - | } - | } - |}""".trimMargin(), paramTypeElement.asClassName(), supportSQLiteStatement, paramTypeElement.asClassName()) - - cls.addProperty(PropertySpec.builder(adapterName, entityInsertionAdapter.parameterizedBy(paramTypeElement.asClassName()), KModifier.PRIVATE) - .delegate(delegate.build()) - .build()) - - val list = ClassName("kotlin.collections", "List") - val longArray = ClassName("kotlin", "LongArray") - - val function = FunSpec.builder(methodName) - .addModifiers(KModifier.INTERNAL) - .addParameter("item", parameter.asType().asTypeName()) - .returns(Long::class.java) - .addStatement("__db.assertNotSuspendingTransaction()") - .addStatement("__db.beginTransaction()") - .addCode(""" - |try { - | val _result = $adapterName.insertAndReturnId(item) - | __db.setTransactionSuccessful() - | return _result - |} finally { - | __db.endTransaction() - |} - """.trimMargin()) - .build() - - val functionAll = FunSpec.builder(methodName+"All") - .addModifiers(KModifier.INTERNAL) - .addParameter("items", list.parameterizedBy(parameter.asType().asTypeName())) - .returns(longArray) - .addStatement("__db.assertNotSuspendingTransaction()") - .addStatement("__db.beginTransaction()") - .addCode(""" - |try { - | val _result = $adapterName.insertAndReturnIdsArray(items) - | __db.setTransactionSuccessful() - | return _result - |} finally { - | __db.endTransaction() - |} - """.trimMargin()) - .build() - - cls.addFunction(function) - cls.addFunction(functionAll) - return usedTypeConverters - } - - override fun getSupportedAnnotationTypes(): MutableSet { - return mutableSetOf(SelectiveDao::class.java.canonicalName) - } -} diff --git a/settings.gradle b/settings.gradle index a1b55163..d7b33210 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,7 +1,5 @@ include ':wear' include ':wear' -include ':codegen' -include ':annotation' rootProject.name='Szkolny.eu' include ':app' /* From 78333e0077c9f9241d8b0e14b357809ab242d0a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 21 Mar 2021 20:14:54 +0100 Subject: [PATCH 011/113] [Gradle] Remove wear module. --- settings.gradle | 5 - wear/.gitignore | 1 - wear/build.gradle | 53 ------ wear/proguard-rules.pro | 21 --- .../edziennik/ExampleInstrumentedTest.kt | 26 --- wear/src/main/AndroidManifest.xml | 43 ----- .../szczodrzynski/edziennik/MainActivity.kt | 47 ----- .../drawable-v24/ic_launcher_foreground.xml | 34 ---- .../res/drawable/ic_launcher_background.xml | 174 ------------------ wear/src/main/res/layout/activity_main.xml | 29 --- .../res/mipmap-anydpi-v26/ic_launcher.xml | 9 - .../mipmap-anydpi-v26/ic_launcher_round.xml | 9 - wear/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 3593 -> 0 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 5339 -> 0 bytes wear/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 2636 -> 0 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 3388 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 4926 -> 0 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 7472 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 7909 -> 0 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 11873 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 10652 -> 0 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 16570 -> 0 bytes wear/src/main/res/values-night/themes.xml | 20 -- wear/src/main/res/values-round/strings.xml | 7 - wear/src/main/res/values/colors.xml | 14 -- wear/src/main/res/values/dimens.xml | 19 -- wear/src/main/res/values/strings.xml | 12 -- wear/src/main/res/values/themes.xml | 20 -- .../edziennik/ExampleUnitTest.kt | 20 -- 29 files changed, 563 deletions(-) delete mode 100644 wear/.gitignore delete mode 100644 wear/build.gradle delete mode 100644 wear/proguard-rules.pro delete mode 100644 wear/src/androidTest/java/pl/szczodrzynski/edziennik/ExampleInstrumentedTest.kt delete mode 100644 wear/src/main/AndroidManifest.xml delete mode 100644 wear/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt delete mode 100644 wear/src/main/res/drawable-v24/ic_launcher_foreground.xml delete mode 100644 wear/src/main/res/drawable/ic_launcher_background.xml delete mode 100644 wear/src/main/res/layout/activity_main.xml delete mode 100644 wear/src/main/res/mipmap-anydpi-v26/ic_launcher.xml delete mode 100644 wear/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml delete mode 100644 wear/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 wear/src/main/res/mipmap-hdpi/ic_launcher_round.png delete mode 100644 wear/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 wear/src/main/res/mipmap-mdpi/ic_launcher_round.png delete mode 100644 wear/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 wear/src/main/res/mipmap-xhdpi/ic_launcher_round.png delete mode 100644 wear/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 wear/src/main/res/mipmap-xxhdpi/ic_launcher_round.png delete mode 100644 wear/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 wear/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png delete mode 100644 wear/src/main/res/values-night/themes.xml delete mode 100644 wear/src/main/res/values-round/strings.xml delete mode 100644 wear/src/main/res/values/colors.xml delete mode 100644 wear/src/main/res/values/dimens.xml delete mode 100644 wear/src/main/res/values/strings.xml delete mode 100644 wear/src/main/res/values/themes.xml delete mode 100644 wear/src/test/java/pl/szczodrzynski/edziennik/ExampleUnitTest.kt diff --git a/settings.gradle b/settings.gradle index d7b33210..02529180 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,7 +1,2 @@ -include ':wear' -include ':wear' rootProject.name='Szkolny.eu' include ':app' -/* -include ':Navigation' -project(':Navigation').projectDir = new File(settingsDir, '../Navigation/navlib')*/ diff --git a/wear/.gitignore b/wear/.gitignore deleted file mode 100644 index 796b96d1..00000000 --- a/wear/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/wear/build.gradle b/wear/build.gradle deleted file mode 100644 index 5b531ae4..00000000 --- a/wear/build.gradle +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) Kacper Ziubryniewicz 2020-9-17 - */ - -plugins { - id 'com.android.application' - id 'kotlin-android' -} - -android { - compileSdkVersion 29 - buildToolsVersion "29.0.3" - - defaultConfig { - applicationId "pl.szczodrzynski.edziennik" - minSdkVersion 23 - targetSdkVersion 29 - versionCode 1 - versionName "1.0" - - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - kotlinOptions { - jvmTarget = '1.8' - } -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib:${versions.kotlin}" - implementation 'androidx.core:core-ktx:1.3.1' - implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'com.google.android.material:material:1.2.1' - testImplementation 'junit:junit:4.13' - androidTestImplementation 'androidx.test.ext:junit:1.1.2' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' - - implementation 'androidx.wear:wear:1.0.0' - implementation 'com.google.android.support:wearable:2.7.0' - compileOnly 'com.google.android.wearable:wearable:2.7.0' - - implementation "com.google.android.gms:play-services-wearable:${versions.play_services}" -} diff --git a/wear/proguard-rules.pro b/wear/proguard-rules.pro deleted file mode 100644 index f1b42451..00000000 --- a/wear/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile diff --git a/wear/src/androidTest/java/pl/szczodrzynski/edziennik/ExampleInstrumentedTest.kt b/wear/src/androidTest/java/pl/szczodrzynski/edziennik/ExampleInstrumentedTest.kt deleted file mode 100644 index 84289796..00000000 --- a/wear/src/androidTest/java/pl/szczodrzynski/edziennik/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) Kacper Ziubryniewicz 2020-9-17 - */ - -package pl.szczodrzynski.edziennik - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.platform.app.InstrumentationRegistry -import org.junit.Assert.assertEquals -import org.junit.Test -import org.junit.runner.RunWith - -/** - * Instrumented test, which will execute on an Android device. - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("pl.szczodrzynski.edziennik", appContext.packageName) - } -} diff --git a/wear/src/main/AndroidManifest.xml b/wear/src/main/AndroidManifest.xml deleted file mode 100644 index 803bc28d..00000000 --- a/wear/src/main/AndroidManifest.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/wear/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt b/wear/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt deleted file mode 100644 index ed694372..00000000 --- a/wear/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) Kacper Ziubryniewicz 2020-9-17 - */ - -package pl.szczodrzynski.edziennik - -import android.os.Bundle -import android.support.wearable.activity.WearableActivity -import com.google.android.gms.wearable.* - -class MainActivity : WearableActivity(), DataClient.OnDataChangedListener { - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) - - // Enables Always-on - setAmbientEnabled() - } - - override fun onDataChanged(dataEvents: DataEventBuffer) { - dataEvents.forEach { event -> - if (event.type == DataEvent.TYPE_CHANGED) { - event.dataItem.also { item -> - if (item?.uri?.path?.compareTo("/test") == 0) { - DataMapItem.fromDataItem(item).dataMap.apply { - getInt("test") - } - } - } - } else if (event.type == DataEvent.TYPE_DELETED) { - // DataItem deleted - } - - } - } - - override fun onResume() { - super.onResume() - Wearable.getDataClient(this).addListener(this) - } - - override fun onPause() { - super.onPause() - Wearable.getDataClient(this).removeListener(this) - } -} diff --git a/wear/src/main/res/drawable-v24/ic_launcher_foreground.xml b/wear/src/main/res/drawable-v24/ic_launcher_foreground.xml deleted file mode 100644 index d36dec1a..00000000 --- a/wear/src/main/res/drawable-v24/ic_launcher_foreground.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - diff --git a/wear/src/main/res/drawable/ic_launcher_background.xml b/wear/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index f14b2240..00000000 --- a/wear/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,174 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/wear/src/main/res/layout/activity_main.xml b/wear/src/main/res/layout/activity_main.xml deleted file mode 100644 index 8d270149..00000000 --- a/wear/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - diff --git a/wear/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/wear/src/main/res/mipmap-anydpi-v26/ic_launcher.xml deleted file mode 100644 index 16e1857e..00000000 --- a/wear/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/wear/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/wear/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml deleted file mode 100644 index 16e1857e..00000000 --- a/wear/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/wear/src/main/res/mipmap-hdpi/ic_launcher.png b/wear/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index a571e60098c92c2baca8a5df62f2929cbff01b52..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3593 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 P00000NkvXXu0mjfP=x?Y diff --git a/wear/src/main/res/mipmap-hdpi/ic_launcher_round.png b/wear/src/main/res/mipmap-hdpi/ic_launcher_round.png deleted file mode 100644 index 61da551c5594a1f9d26193983d2cd69189014603..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5339 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 diff --git a/wear/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/wear/src/main/res/mipmap-xxhdpi/ic_launcher_round.png deleted file mode 100644 index b216f2d313cc673d8b8c4da591c174ebed52795c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11873 zcmV-nE}qeeP)>j(mnvHsDN`- z)Hpc!RY~GsN8h7-e0h){1pPyutMv!xY8((UfI!|$uSc$h*USS<3D;)>jA&v@d9D7< zHT4Fjd$j16?%uwChG$oUbXRr5R1Xal{*3>Jzr)wyYfFQK2UQ7FC4)xfYKnLmrg}CT zknXNCFx_kFjC)(1$K4CqX>!La*yN7qWum)8&xqa=WfSER0aGsfzxV7lce(d?1>-gF zT6j&oHvWy`fRfqbDIfBK#+iKbXJl;cI`!U`>C-Z|ZJwUFC3f0BTOUu$+zK-?w}I2c zzrg0fKA2AaJ?-8WL7Gm4*T8GxHSyZ?Z`|7&Lw??be;eC?ZBfFcU=N%Wj6KBvZxnGY zW*HlYn%(vHHM_eZiRe8Mh?L<^HSumhuE(R}*~|XjpKX@0A;&bsKgTTHKNn@1?*FMI ziC%~AA@9X&;I$@Z1myD9r^@@g@42>+Hj%br8^zmsYn%e-Q zJ01asY3^x8Y3?9WsvAD%7~OWuCO_vGrn==C-gf&mAk`CW|2+V+?`;R8+vIh(-2}>= zUIVX%*Tie%-@w1c|4r5gk!Tx9TaD8^OlXWGW|a;qty1|t3YvTjXbn@{9SzdluNiU^ z!ztArCo!8S#{egkOmsn+hyeP9f?z06_+GpQUdx07sE`aesB*~9*{p4%w$iqfK44!8 zx@6^ymlHUykB{k(yz9H$@Q(YNJZRid*#?}2DRtuI2~Z)RxHe|9HgoMKeZf9q-;^Mg zAvod#XmH1E(8!GSL2i$a!N?3>9-M6U>6U8ZD-xi55?LlU+9$4W>w}EbJq8yy4$6lF zagKOwV4UiyM_@UH!0>}S;_kZa;@nfE0!YlwjYwaY?fU3w-iL$qnZ!)}#A7{Wd{oLq z9Gw0ct2>ZE+$|R0d_r(sA0CAfch(7>EJXweg?*xZBOuXODX-tVaV&}&Bjuwgt3!S^ zyzOpF2JWTUAm-#7|# z`yNb>^X^rtA>vKwyn8#kxj#Pszl~4MgXR5QS#vXYfKb`o-v`^DgwbbNu4D1fF4*v2 z5Sg%JU@pUT@V$5qycS+lLHd@3W9^c8=*iT0FZD|4&iEj1N&3F__74yKyMc6Q=hKKR z$AAAMpVmJF%jMw_*#9h+KFe|)Y{$+g;owgu-cE+=;Ct~JcrC^1TSOL)`I7WK56myD z?Odq>Yd(!MxVpO0pgUeEgVWcLPsL6O&#*La7?|cISZ3+|;Q8i!p>Z7KX9f6f5WwIcT{gIli9H^Jc;nVYHw=1SpQ z7lFssgJ0*VG=uy(1H>&jX6yg$47#zlJ~&4T=gRmUVS`&PV?_nyY>`k2P{sF+&IOs1 zepgq5)&=WH3bl*R)7IZ)QRxyI=d~uIkcu^ap zN`MroZ&;vr(*<;6Y-7lreO2M{5L@M}qJPWPMLh0N0;IrwBXiX68gXU8HfwS2Dr}{i z51I{9R_GRtdz1hvZr}KLNH56=dLNnJzhWTDGkaBuS&S>Grbh{o0``q}Wzn|DWDcv# z-Ia-4*G*UJ;#`*!AO-Imy0R-PK;!HpNBLSIZY8sdW|Un!l65_!uB(KiFeN~W**8|G z54v#<&%fI;;~QGhD34WY7W-5+xaGE8l5$ifKnmP9TwuJu3N+8#?87-N_q3i5ob@g{ z=@58wiwm5U09B5@@d34Nfjz^p{BlO8uZPm*N2~1c(`A;i0VI1*(V9sHAmT0=YhAe}LpS8KjTfWEvwOeZ#pNb=wC9g*co?D^%u3 z?j2;-$LZES9XwtIMH=}D8!CymJqe}Nb{-FpgQV{%N`8;e!NaWQkeizeS-IKp=d*Z0 z*THsRd$3)yv`5yyxj#GxA+P?1oZKARC+r*cQI_@y?As@tQ@d-sVAdZlCOFs5Wod=@ z%xhHIx^2=~pR%<;)9-G9lP@m8$DAxW;CJ3XhFSNvS6U0S`2O$kB&vH$Qx_Hth}coORr_6AxujsJMnz>RD@nll zJnIb|_y-@K!;HJzDjh%${~m;w*>7ndurJuBip(&vY7ysF@8WXk{inGz&belidG)f` z^FmcKxape2Quhi62n)}TJx>x@p|dZp(0jBh3qS)?S3}CXe?->jFA~dPpDKKbf&hdd zX$4tdC39YrTb-6+kBpCfbmQy{_|s6Oy&bu{)=I`_1i;g**P?(L&ugwM0HLem;lVy& zUld`DOSG^UXAj-CPaTGHFH=g-OxRcbt~vV%abM*L5L%o~{{_Pb7EogfEa~7^BtVlh zHo?6Q|D$cjwqqZ#FAB3rO6C|#U)2v;Zo#=1?#7t=>h3(QuEA~B6lsHJd92oszO!Bw zP-7P3MLyX=1{o)CXxdtO-7zF{`7wP1)ufC-m`KF`8~@&L@|wYEYeXm9OVc;wR1Y}# zEKZcRW83kXinPj(b4=Y>u+6PD)QZ|~AY%-^5JfZyY@ z;PdDdZIdK@o0qvm3R~qoy*wCm|ueH}s?oID#m1a>0T9L-7zgcs8c71)cM1bdal$rYTd~bX3S8@iZfsP_S{QnG z*)Pa~BBT^>#2 zAY?+KIEckR-!2*1bV|miOw$ZMg>zw8SZ12;Ph$ywKdCYb+m3x0o9?G@0O6eD+>Z`- zebCxew+)ShB&ic(rs^xr6V@8jGPh(=fMob;rSbsC=AXTg{3gB9f>Th5Z|;EgKYJ7l zATsCZeasTPvb%VWGp0;zm0(qxy{KBh2-_cLWc~sZ?goAus350!;UXb!qGGE2xxkZ` z{=XyED3SJ25l&yj4d03P0zXZ>`-pw5=o4sBwhs>EEWEQ52K;5S8<~&@AQk8S7z5QZ zy6${zTIN;^R&$Ih@GNEA0>Fhhd8{HUim%q%h-@J*xKe+>h?=jE(6`p^=@bJPhz_Bo@5Pw$X6Mu`BiRp=Vs11I+;(f>zz1B9!ne8IW23c8yJ zKZp3i_|wkxIpY2mg@ET{b`~7UhyaV2jW8)}HP|QafJ;x(1YHZq2FFO=0QHTu&+cqJ zSf8>{(rPphP`3>e`^Xz0{M{eVVg(IsNajW8xo0Ny+B=KWzFDCAhXtI=h_CR1vYofj zfzC-Q&^T^M^fQ(2sfB_eI`B9OOm2C|7oaHHEQtVO=Bb97w^=XaRL^(v1PC*YM;~7Z za$9I|#NpvJJ!mz&{7`Y3+_U$u;Kva6eDG+T;N+OR3*HKFXOG@LgIOt?zz~bRLdhkr0(BK)4P>voPD&ZRhsWmKdN;3kQEg()j<$ z3m_~$7h2cz^xaFCeSU2rcu=ONS5hlbQ2;%C{}M)Ba4rN7$|`;{y!a^0I^z50By6A% z8QgR&_cUJj!jh-0$M#V#9UxYT*lM(PTcew9neqS#|L@SVc)_>VV1{!nEebUEo9BZ^ z3% zE51hhef9?uNC(0AFi+4X!SjUh)v)hQi0szw!z&mSomf-}y3HYsrS^#9cjn^Aw&Cw^ossr>Jb~*@xHg zkiP%n@`hEC!vB#h{nq00VA&mT5W1 zC>fwu=9;z1bHhfQ z36vnnrYq0WK|j=1B;zm#Sdg%ZS|Y4yl(ndSLXr=txs0+vCR&Y@0H7{b-(wb5udDm$ zepBymeqUa<_25C_Ut*?5hlcVLBB*tFudt1(``Lt zqdY#eoohH0ndmU1f6Y<>VtIa@hJ8A=pPUwufdJ{>b}jQ83-RAyQk`?T)lX-C1e+_{ zDLgu%OF%!&mI1T|biH9cW&|WohA+o@jkO-hED&Kd(K)OM< z*@OCwz2p0o9xx^FfQ6y}!h;bqKRi)ReizW5pVjxV6BLMO6L^4I$GKgGD zKeay19R{7Zf6;NYjv=zZ77?pR1`q~IjT_e|Kerxrb#*ubBs7pN3ZQZ68zJ+}e{}0X zI=zNhAKubuY2H&vAGqsat&sTt2@zi7)yKEezxQK);SM|Q-Qjb=-<77!xBr9DaURrN z=||WxfV}g-Ves(kcX4@%5aC?ocZeAuSb#^|wWBOZ7(j~x>8AQ>^~iI}!NHDRWew1v zTdQGioIlJAT0`UoGtaNduVB>Le40gsg=1@@_QHY?f0%W_8)k(R*6dIprgeD=ns z1UyvHb{s^-xG%IoeUltPd&Bf?m`pX+?NVRT09q6WwHVS1GqI)`-jhbs6IunHlUQ69 zW{~1ci>->PB;-pn#HGG}4(K0T0CSG71_Sb}{>R)r9pu#ePjgOx%`2=!^QrnAo)6kb zEMfW?PZ)h_IcOZUfIhsASyFLDV3x%egHfGY0GdRm=UreX0ay3TBG5cz#p&$ALee_7 zC{IC5=dC#fTZ2i616apyfdL_oq770`i}Q)kwy46G_+S|UinJF4$hI&%3?K^8rNWko zKOd3&tsFJWAycFcp!3{V7a9jOB@NfYA z%m7-E2auHTZ~$3>X|M~md?J7Zz=ImV0~G2g7#@swC_qUBpm=YrWiA#T-58=+glI)R zh;WYagw|dM=G-K6{|#k;W1)(40I8@{Yhci>5yn9pXBPUF2SBvJ*H+PqD-9m?0}P-O zUIZX3!SGOkjuL>*@&H*%2ah;Fr+I*Upzj%L!SJBPLCcdLAnD;j8I%N&I6OpsW9?}{ zTEELH3b`+}_2YlVxv#I+rZK%ERZ4)wdw#-l>iR~=uZaF zUsi(Q>2t(_0JMMrw3-7*faT%g(c%FjF<0NS*2TjUR5CmiAOem}91oB%cre~Eh_VOE zfHx-s22`&c1XNYbKu zbY~b-6bBDl9JD;*011Hy-4zeenA03ULg1kQ5tn6l!4+na0KFhUl3JcZ0EIaUhKB>l zfdeQ(44_irp^A3^y=yCT^~s01=k8f}8b@a~_cf%Af5hEbb!Ng^_u4(%fj4pGbz`Ca zb!R$hMZv=ZH1{M2kWhFiK*tuqPv;mw0^z}UhX-hO0f3~12VE8gD1Ive$Vo6f2upr| z>?DRqmx#EoTVLjfYNhyXfgBemNS&$iI=hyx@99tu!2 z0q7zDD3JgpAv_eIM2FnI2@cR>_ssw5cWa}IbKX>~X+5FtE1w&y+ovU-4b$HEwB4_x z(|pVQOLs@!@P+|F_F(kaLZ(GvbZ8L_J7Nn9Pp^mXkJ^Fp5o=CIZ3^qy;yfKkEdk>b zocf7`Eu%6ygRAXFW1N;=~4GSXz zU`VhN3=DRFffrDYFfb%fgF>A06v}Hk3<~2kID9#bjdX|QiMzlw$^!;RtboChsFg4z ziq|R_5-l!g7#hPAi*kXXaV{`C-W_Z&@1*NQ!{S{zB@iXLGf+qp$^S=?8?Y^-q?x+>kuz;fKM73l{)%HwOloih)?&!PU*;_$LM?F(MP zyI|p&^q+PH$aU0c=q+d8CZx?B4@~@mOa$0t22PXmz%Kpl4u=&O*@JTrgwpVvi z*` zVQP?Psg`Fzk(P%OTAUeS-V~al7nT>YJo&6o5te6AIA?tZhp(WPXL-_ZU>fa7txwUG z#~Fsi6k&Oo^+An53v^`{U7a45;8vvN878tky!G+SL2IYsI|Ym9JJo4U=em}x?kj&V z-JJ&0Z8}&F979sRY)MmkSq~b=bt26(3u(+_cz7YTJca}&X=0v&>pVIqtYF4@FBo%{ z#6YF2^N7bhh0=5)y!U-hxG(4hEtV?gDVVAc40obdXJEu~sbZdj>pTWAj_~uPEigH0 zU5POdRRWEDK4Gax??23QnorQcmFG6~TGx{~crFMKl32TT`=)qvSr?5H3l1CHaFOUs z=*r@xdV{}R=!79S=&nQn34kXbK<5aYCl*K)Fc-H-C<5sGV!`lWpp4+;14sZoB7iP$ zg~`dJO{Kv@q?hQJgKbdrHa&}TTf1rPujz@b+?_ziTVVhXO<_&X1uCpx`Bf;mHrs3c>K8 z4C5SO0RnVU44|UmNpPgr2ix4mbtGn9U23&%+=kXZmr?Ls^vX0xXuJB|+iH_e{fmo> zC9O`E^_Q(U|8ociT(B1m55_wP(98>KIe<K8 zyE2S(5(B6xaERL?@aQHvaqB)ietJ|(t+_t6KCS9CEsNB>#FU;|A&%6}U46$p>S0|; zn!DTp!fbB%-)rbZQE;S$2ZbkuQGm|p0VEYXB7m&n$1o2LpbJX`!&3+#f$)d`x=H}L zL;xzn@*q6a`XoE$;yAUp8SH^`S>Dzse=LMs{IzPeCC^<+KpjC{*=^Tsd4Ay>ZouLs z_7PCeLjelm0kRSV4+V&r|8WGMxlw);AffP}#X)coAX?ij5FQFpJOZ?h0JJ_2pn~uu zIb~~;zuV1kVgi}N??}SlmX+?PmY4M@l#$ix(5xk{8MK(7F+wML*}LNQ$;$H^3lSom zENSa`bWbf30i-3R+Y(RJDL~;x03@KEXAl7h7YGMMuM`XqJu3(Sy2b!1;I=40NshUA zuUOALv)?x!N(1Lk<&}ArWQA~zpnlDk4Lgu$wQhlvR+ETc?f`LnXRA1fq^Rf7J-vul z5n?HZmH^AcXIt9A44`O#df1aJm4s+{@&P0O9tu#xat4r}2p|zWWRCix>pE%)o$SB& z!?|N~Sf9;lRTVircq>HD5mIST6OX{}rvB%=;C@$E7Rt)x@vY6cCWR9!>8?5gG>ZpF zhB8zNP=se5Kr&PkA~?7;K>-p74?Sp#0`v<^x$GwbhlfWmiLLqgjElrMV{_M-&81wd zPoaQXg)@JhYjtg|r+Lo$K34OKLnN=S{ig1W42~qb>R5i744#q0W!}Akg#Gf z5kN7k1j8c&=sE{bzXI^+lGkh6nmljYr;9XgVg#%`4M=r}1 zkB8(15MK&{lUiCCDg`LihXCYCwq3RHgM}T5@fP_~PB0#t)S_mL1;NbzXy1pHz zUSR+wvbcw2%jyTrb6ZW(wWO}AMT3s?elIx$&ZW6B+;nSFqgnkfXcoJ!pXf~&v{Kza z;VQK}0pi^mT7r_cC$N4Q0m51yErIY9256Z~m4pZm0yJ10ASvO&c*ii22gskE&e0e5 zx-KsN)cddnbhQ0`BhC?(O(^PY3Czfw(ex1H`*C zoVen)Cn!K+>k0uRZ6%=&0d;&N0VsAuK7fQ2gHeDk?}Wjzs|3S?GD=(lRw*1ndWlZB z-jkzo$_l=59djJ#hRsp)igaDYxw3jHwW&|VTS0pE+&eQAtNV=zMDhkGUrbcQA|aNa zViloTh?@u?A!Vo>K&$fsB(#!nusA>h;lX$(4g2t1lW)}Xf5EQ-vDI-Q$ZDy`{U zRiNuC$_iCwOW+M_HmunmeJoLLt%H`yCYPPT;{L8|$NL9m{@QP|bbs)Cc!EAl^7;X{ zJi#E`9`w%GfZkcAbBn<+XerDK^Mi>Yp3pC7G0_s}cb+Mj*HTUwIO!8W3d$hV7N$h4 zg`eXB>B(UFVRrPC45|oT_ViX8PQ)rli7DEVQ;Z}05a$LCS9ZhjcoH|pI&q3aEeE4` zrUXvL2`e}yiYaL&)xcyISbTj4%(@)|-CH1;^;^FgJWX%t6sxoc&-GLQ1-6ph+IVx0}#d4ytT60SqLNUXseVpoy10dE>E#`?l5p9Tov`5YR!ak`o(E0Usf z+D>B~)WVcsMOvJ)0|L@dXFFfq1E#+$zSF2(GXtCpHYbf0A?_(H9>NvPruEykRC|NSjnmJ?sGvT^&9F#0Ub`(~&A0uy7_!nhC*B6pY=>IqKKzrv!( zKp0Pc#zVlxg@=JtMWDQ3LL^g^7fhsD0~4dyz@+H4uq0s{I4AFcsj)sVDRwQ9H%y8{ z`Otf_P?M?F!Q=!^Q&5R0Uzn1_32T_wr5vG^gi|lBC-Q@-mzXYdns(VgPggcjO~1O4 z(=~kF0JBpzWxEh~ChxSr*P>^qK{yBXo7Km#qA8o3YKjO?zUoC5pf%$&v(}nwCR2~O z+%igDNn#=o!RJnoB(V>E=^8#u`(8tmo#AmOT4xs#H)cbNzz`)LH<9|mfojM6=h3rx5=kydl(Yu z40cy{!H{@oS_q~W>p*wYMZ){G;vMrX4)#lM;)KC65ym_ii;dZ~IE}%>XI#zLoK#n2 zcnWTH(A$A(aP)U;)UK6&pFMMuaWMC2@xPX zlMv74k)@JwFagMx0^}lbz^uow^I)ou0WSjJUXo?8`V2@yv7 zE$X$d_bqwuUcGvCjqcm0h3JsMr0YbfZgkO6UI6jyMEWGi#h3?cdC>9*g+~_wit(Z+ zf>D5Es3aUrEDzo_F(ko7VtD%IEfRjxII#fKJjX_mG1kJduF;f^c?&iN)fFvhmNYX{ zWgTeAI@FDHuy?nBiGSiG@MrN!3Q<`AgzA689W0VJ5r90X+Y(wy$N{v50c0mrB_UcK z5kLjuNhlf~+@8=&UQVksyEuSz?$u_t{+wP1=47%}>)g^@T3G^w z3!Agjx6zK>w;rc$f$*r- zRqd`)Q>7CNnCmLiLSb3PM0Hp?*^WWfvtGMq2HiGKzMw@c0lify)h%0I0O1O`;ol@X zi?$V142Id32%t!NnJNhp91bAY;>%EzoU+mS;Jy}#cf#tnX=sdNsM?}#4_edAjcuLE z81qPKiK?@;2;9hPOCaio`!g69bzV7QZJ(o-Z*YL{h*^44Rsm~N9sn7!`_AwfTxsih zcz|%B5CM{N>A7>pn+}Tx`Qn)2*s%{{TQ;V(KSy|q zT5QDCP(1ytl}f!D->NpM(-X~blcC*4ciS>03WHkymLYMsR$c(n?Cd79L{gMw;93u! zMTh_y@Bj%c21Cmu0*Kx8M?Oqgewu^7$3VI38q=62`rnvRmsLl#CypH*LvAcK3M*u z;3+CDs>ODRTNbcJy_*mGc8r?uxZ{0J{QLpq1hhaSGkkOS7|B4uH_?>#y`l&aPI74_ z8F&se9%hLrf)xTt0(f-U$zVDpvl^Q0o`XlM;7Mibd**!j#&y)mCI;V*EyC)wWMft9 zbB}kVwMI4A+C@|P39CV4qh6Tq;~=&etvR{RhN-75f_&c&j$H}taEDL4dy@tvNxqmC z18WLV3ELA05UwQ^0;m*ta65;@IG;$YlY?=NZoED8KW7KC{&IV(?m7NU^I<)vGH`m) zF{q*PEwegJ*%;OMQmu}p)~EsV@9ofJS8rGc7s=FdP`eJ(HtoH3;vNzs-KSr$c4Y){0F$KOY>eN6Od%>}g&Eh7L;yuQln4*HVcj^pPdW(>xw-@z%r@~_eU4i~k8RWL z_gFc0?>B~h%osT8w9lNoYR|@^fzs+o7aP@K*+ok_h;>!J!)%SWNVOW()9<`=sC)OV zQxp0evwW*VCJ#^Wz+-CJmxbgM2b45ljZNKIoPCjtgcP6zA9^Ms1xO4Y9qu6SPsG~f zlK1Bji$m{4*CFwh#_5I7Ywzs0UDuCKXlr5YLHc4KvN&}}A4y*sI4#*2)cKNQ9ii5! z8Z*^(Ss~QdG(IAqN-@{gn@F?854|RR<2-6>&z(PA(L8DS9w%6zSSEzShyX<_RIU+q zb*{Pi^MF*(Pqz2>!|c1i(62u-x?Qrc6a>pD3a|6n!Q@153Xpz`!zZ0+yIdUvCe|*8 z#5TD!K#t?S!vgD)d+nd|{yYDPS324b+uC$cx5?Ocww^;>l`3a(I%)#$RH%s@+&69twDR~x`*&V;!krzF3hsU|*4v!~_ zbI%zO@1A3EX-kgd_1(E+l2*frBoF$xzK?Q-!RH;p;NHy8uHez)y7+7{vt*hEiwK=g$s;azI!U@u7 z+_mkH9_B+9_I01K&3Mba(4l`UO&fmN>7{9eJ6K)Z3iGdTfk}V+!{pQen3}#BrrzBG z(=xXftEm~AVf>YKU>5HMrZJu{Cc+J7gnPr>3qCOX1WCmY*u3n&ZGM`b&rhM6PG;NG zruJXdxJ%oi%+mCs)`ql^S{u@4Y&+{ibJi!N#gP+8s%+W5KFdtLW_v-MDNJO7#4M8t zD5Abi^g55}ILpvV%fWPw&f3Ypb@Q8as@JyZvAy@rPSH4Eo}qcj;=b1L1^;QETKJUc zxz6cD&$Ul4e5!R~!GD^EE${ch*`klWX)~I*u;f=K0jie$!X<9PQpwA006m`<{e}F6La+= zCd8M<-#v%`fZtK;j*4l}+;#zxjj6@lrQXeft0k7uxxrm_q5=Z^mah{O(wnZ5c5%MLzTW;;&e^OY}{C ztn=uo)88w2r^)?25qlV}=l{KscK|wyNki?gG439O9Ob7R3OhtCXdyc=$QtU~O_t|@bak=wm@0{To0s)&_Zz1!!m}mZOs<$X= zET`&U*9Oz92!>_Pu;{solz-KYaP!x*ake?!GkD4CRh8LAD2}#rNlS*SKyLViG_!I( z1FgP^KFw-}(ir1Q^VGs4;=q_V1Jxr{Y@h7ZOUgLY>X6yAh(($%rQIVRuhH1JK0$?? zDVETM)0ZlvrEy$>Gl;7A<~rVKXEWL?rYzPOP*rZLr_Z&ew{A=BKHnDMjVTFVF^T05 zU+CA~s#slbJC%8kQg|J*jjotd*)yq{R%x`cJiWs(;{koDvs7e3|GgMLTcTSprt+cm z$Qu#|^U0zRF3Xu6(D^SzXUTeo>HfKDw`H-FhLu}LGujq%FRt(A!YEt+U=FLE5s9qV z>mp~3l~Dx;l{3-Ie?rVQH$N1%ki^ZM|53Ck`L%B0?e@o={qdjI3V%>D&t^oczm8Ow zejO?rJKz^}X-5yo|6PdRX6q_tv7?yoMmo8|?m|$Qq^Nyr%K6TK23~y>ycU&{~1j>eq z9Ks%pHs*?t6Gd*W_95ED&{lfYk0tA+@CF-c-D;(j`1uXsgS?!tf;aT*MYD)0Dcg)Gf>o-L(^(hCWMLVT>W-XzfyVgh> z71+re>L}QeGnM}kB`otCsaJmRKk4<_w^M8;WaOECJ*n=8y?`>B2}f;VMFhk6VTV}F z$RjM})O8LL!|{8oejqzB&>a}!wu!+hrd+eiD7$8DjL&U+!Je^Jzq?LEg${eYDq|QL z1cP#raZbKu;)z6ve3C72s_MjP6+JEle_rU`Wr}l{tcn7ljGAj_Hh>74myG*8M9H)! zZdZK%rT_66EW3W^I_aEy6;S&}VV#AW#L!?t-UrkQFq0@ZN>m`p17ur$|QOx<5RQ~W_&MB%xL7dV@g%DwdXyX%4G$lRh{;Nr9t zXkn+r-AhRXfMZ=raH6O6B{$vg@}Q5MZw1ULmMOu}q&QP(9qUcP#>2fRU)Clyw1paI z;b-gpL*S}U1qo6-M95i>4r_+5;u}{(sTRquUcNw&N4&nsjLd0-^euj30NJHNi65Wi1e>h&2Vob#rZ8%B4Aeqp*24#Hf89%mFnR07bX9*k5qv~pZ$~Bv&049y9 zecv-?UEvhXde2-OdzUO`Q9CXpD;ZJsGhCA7@GKov^@intitK?(UT5M)C#&{ryxeX4 zUG;gd!oiv*MQUV`S5H*aV2bpE0`mYTNN zgDMeX-veiiXwoY~UWG0`&aa&D|E-GUp$ED-C4N6t%df@k1u~1EZ5>R$gMg z=(pN3C{Ez2Z9sKMRA}7j43qs&>j$QdOw}T>g6pP_qZS_j(ZvAA_D>_BPOA--@uS~b z=pU(6nD!b3KEnK1rbu$nwI|EUJF@CDsQAj_?tYilT9AEOa6@dd`jp<>PH|)_{D1T1 z#xesVvv=9?oLBWj>48m)xM?dqR(Dq!X`gXApDjBv#MmW2zcy<%Mb@55tR%Se3Bge| zWcR855UnnG{zkp8tFQq%nxW~u`ww?(v{ft(z4*Iive7bUr*DSw|%YaE904Z zg{vWQQ+U$&HgW2LK2BY7H1;RccF z%W9%LoluENSHos%bNi&CP*L;$Of)~u>^PJkv62)NY(@PqL>F#&UHh)yiYL*2GKWlO zi#XLn8Jz{X@e_{OO*d|vkRTlj=vY!*MrfDMdw^E(d`W#?^tay?5$#7KQ4GXqAHJxD zkGGy^_mlEqFk+8n&P?>9@Auzddl11CrKDsPo&w zf5lM3T*L6I04aY%Fj6}Qq1@d3k+Rj5LwL(G=yHx1L)_3MHuYohe!n9O#fm1KPzL0c zP(R9Sn#H*vZTRySJ_6xPy$gcoXnQKCL!xctL0jfQFcr3c z&jo+~#;V}%_`1Ev&n6Kn*ni?)Ut~xUs+%t@m)1RFihj9Tg$?~3DzEos{O{RPZ%7C| zvnY!&hlyzTUewaT{-%q|-j_wJ7-bR!(|LB7$8T6$T{dj2k;%U?r-c%Pz_EK^Y<}Cp z#r@z~tFT>~FpH&c#UarjzyIuW-cwB(pVAB&Ryo)P4|V#p3GCRvE@P{mI@c9dp0A2f zu9f3>M0d1gKF`{Ef|L3p->P+SdH0sLQixnu?DWcSYT|dOG?p@tS3O=ILVFyU|4hE% zIdc2i;EP{l1|3Wkms>A_rXd6gk!%wqn|tFp*r2#5Bzkdbh3Zm=+J+mHdH7DKCwhiN zte__}3pWXjFOwOarn|7@%KWx_HB;}siOlK zR+XE$-me7BjT+tXWB#X?S ztn}K*Jab4!Fok!*gBuuWhy6fxvydq!Q*X#*?)FF5^_fqn_LgWt2D$9I`82goeu%fR z!TH0;Eb>%lXf_` zR$b6ml)W@-+X_AUEi~dIWL)sQ#GA+d=eE+5%o6?G)mXJAR%w%sTb}|t{|l6+9=^w~ zUJnu4inQ1qkn99qb6*ymN*S6=iw3*Y}^?WbKD_OG| z$U}o#TJq-T5oqv|w5|P5279l0{tDaAbIB(}#}dN8I7cAq7uMe==s2&tW#~n9-ZCC;pWNW|TxL(LE8LTc@mZqI*7oX+y_&V%h1c$=-sfXe#J!67BW5eU`y4&jAAMd5&L){8I49A(cAs9mNf{t|Aqj+^!f9Z7CX5G|@Hv z;WU8=na%*rCo@YEN9^*M5DUlO6T9EX{B8WbN-{0)gt&w3fuJ9Lw5Pyvn11FsuE+nU z+*5i8XhE3gPgoCdgL4|_u29lmsQechRfT!}}Y2jra)p)QFcRw;DZ^>vWZYnI1@1wjCI}G}uwScRd=*TQ-P=?$Rwwb1XprSCVL^0hk^hkHfJ0>D zQ0gjJgL=P|rLl;NbA#A(24TmNbTIKjY$S)qSS}-6}dcmw#4oQ|ptbv>Au9q5g zDFnzOXP0r07KBNB`U{BbVziFi*=#f+bu>3s?G)TU)r7SIH7*GnFvJsKn37mX_iJr{a48G=gc^#ZLRq2v zl~wTd_xzOf9JaQ=Xm7F!n-$ulkRi^#_|e0Ce4yO@Yg4qw?ILp4`kp;pnGXA&N4GaQ z(M285>ovF zJzq~ruP6+0RIUx^^(C9UpnhMC*@%%=;Ogf*lUY>(B|bMq)8oev4HHl%B*BhxpD`Xp zx~2hLH55uO=v713XC+hcS@B@p$|1j{3c*P^judPe4;GpdI&*svs?O5L3qCdkS>lcD z(;G`%_ck8zBv+#606~epIF+sO>#+`;x$12QoA`(`X<)|7HGw?^oiNBuprzob?<>iQ znh+Uv$ZU7I*0FCgUQkO0A2($QIrfb$M# zR@IX<1W~~X=O?#*OT(_Gf#Cggs%(~Zb(A;k){Q&*cPpN#RYR9e$r2l>pTM=0JsfNr zNG+W`qu4)pI3SCK$+VkjHI2EL>fxGJDopv6>dea=DLa6p_;<`ZB&laQQ`!<=3O_<( zQj0?;$>Tv}ek|E=;7c;4RYFIdPM81QN)5p0=IOfcXmsCd8hiJU^4K=X_?E3Av7pAne0?v_c67v2D~<5Kd}?Z1`066k_+- z4N+7Liguy53`HfvN0gSJYrZOVyuL))gEfz#H#(vBsM$|k0zr#}j00RKWO~s(hvM!; zH9z9x`#S`A=}C2b{K_1%hR(hu4Vm}y1=8N?J8Qio&e_+oOvTj-%RofhxM!s zGlkP=IUUnz1yZWi7YGpztUX4IrD|Bh3nROBb8S{5Y@2rr70a;=tD$ z@;Z^PFvVtS?akp(2jjH7-&;JK$)2)^M@S0DLl z=w`n;hbp=8BQl!%L`wZZXwNXdktbGKC~r!~>^rpv}IRweYExXtAchM>lx+nxaBwkWXA(U;~`Ou1@j8YMUPfHzD8`gp*Q`yepy^l z1U=YX4&hF5r1*xB7hBANP9V-20ADw-3nLx}C~2XLwCfmdJmzIVCNd!SKd;`h3)cT( zoxCLInUMKeUziLWt)|eSj}Vztp~4oyt^l~$5Ky{8)GVkbj0S>-SOH}kY7RL_z@&V3 zj6DtJ;D9#+V2))scw7uj8lgEw029y#*VI#j9>lZ;Ly@rm#o+p1BedEb^mQY1-7ARA zfcW51RSS4N2zI#|t~3`Q>lG!&0+Xa_pl6k&6Y-=){Qe>_XwOxziTDO24Jre;h{CtQ zLpdGNwKDf=x-xlFGz+Kli2&~vbs)9SVG+DbW#AvA;El9sqzJ}@3iI-zQliN3m>up{ zxv_Zs{BBN#ZKc0bX?e@^%A)if!BB-3gDcul0W>o36D-~sx1+;kk>VtvjMhu!;o~x& z(QY)T{NIM4Wizk~Gv1QJ;C?wVn9|Ok88`_4q~~}_>=R4uBY@UAP6hn}vxu*O<%K~T zowv(aAux%JAIwaiH%Kv@XKBFjXVa@8oLsm-668wy!MVgm4##`bhoG`2fEwx!U@wB1 zWKhmTLz-(wh4?V{=s4zb{~>fd(1VcbiPyr@FuzmRi$+kX6MpJ$ZnTv{HU~Z;q^UWg zu1-=@csP1IhR^Zb1&Np&7^sZwj0eaY3%cB<-iS(Y{@!G1Iz0q*pceUaF<*zYNVqH2yb#@SY4(TJ{3tg z&!a{!lI*p^IJ73X27ko2NEZRKn1y`6)6+2>!kF~~-_e$V!=3y&j_bBxzQf_+HrxmDBIAP{E+Xg{TWMTfYN_Q?@&+bYwcSWj473Y9Hhgp(DXpS$Fpev=QRPDyATA+Z8 zo-kT(r zjwl`?IM9jC5Z9hj9p^LI_IP6Cols~?Z~P#bpQWSr4&SzW1jM>w##sgTM`kuykUl>i zQtd`)^ECC^w)N@V;g1D%2w|$V8^@R^h`nVBA2NrAL@_6{0url*;=Dj+3n61(K@1s6 zwIQGH(mef)zgRIA8X$bwz9n2IZ2*Omz@xcELA+ z#*RBlpFQdJKW`)Lc#TDnMqLC#0^ARy%vMD#%>oTwAEM+Em423QI7{1w<}IIkTbGOf z3{x)f9W}S~buIjyvgJTtDSfkN<)abtJ2p}s_qXCz@kxi*rI#@W%VScVD1BFiuGV2u zvS2Dg_kdvLz!M?*i6~&jqEgeROjpa43$}-@_~7=6qY7e7ZD5%~O+ zGL|;n>BAQmQD^e4+rMov9YKN{@Hg)J`GtOWW2&tSR3Btp(G=wyGZdY_2SiH%0hlfn zH1wVQ^ijnX{9GgchYyx^RO(RV6h*CIZZFZ&G~F0KJVw8Btx~egXtkN&^aEu^)s^nB(z8O&=lk zA?I+{7{n-9X9Dt*A_gPekY(VMzn4umS2Cvo{yZQFGNm0;L$np2vMgMA6RI4bbJimv zm@ZXc=Z0j@5h6+X^%0LhL8Xn_|G`cgBRpHeAwH2-_lto~Hb4y=Irq02YuKE;(`+SK zCryo3!D9%Pj08K1@3+Bkp@MEyxgtgxK@vmiA!v{t1T$H+G9EmMYuH#~%~6F6&1*t@ z9Pt{;4>OGzq2;~tqUl|6`1w$J8i`?7CMm81hPJ3aO-*_d>Y?|IQKM7_27c9c(;ew; z4v>FiGy7=Z)54l_W@-f=hL_O*g7=A{d>%_3gBLXf`2`~a zLs0&QOf5Jux3(FuyYD&|2c`cMk~f~vf_D5t%p`aqe!A89%}?oa$n=2?0oUhx~bjsg`VO}G2FACuxVVfj$l3!l)w@&LFBTK5rNdoDlQc;Fi{BvKSl^bQZqqwWvr zUuA^5Plu@&mEqPa9}cIF#_jN{>zdCw3k&rYO#Wp-2LMGVo!{L^ee?Qk}IfM&H>n z>)zXizgwd04%7W3t{H%LbLeg-<=pwt?Mt5S3%?<$m6}dk;i5&^tVKhxo)XN?6yyZ^ zT+J4o>TXI%QfEblHX;ZmxLV@US4R{#dnEM#_=2J+u$E`D+&h;1K&zfcvpKWJ8`&Z-3#M%}S1FXZ78wxP#q?G{jAyIJ zJCpe<_`G5JzWRC%q-uE^vDu__Fl>80r3~Dit-6*T!*w7^B`b^`-%e$;`T?5GSgI@X zARyxlVBj;39Og3-TGBQMq~Pc-O_5d74@HP8XdYj-hiH>I!^Hm_UUnosKrhfY9#+1E zP1woPpDbCkcgBIwlvK-5?(2_}lNzEw$i6^Si4h-EMrDY>qtZjxtz-M}H|o2BsoG(4 zcXaIcxvNEE1;cCA`Qhe|Z&taQH`+4!NZxg|>3ls^TVTad{$+IERDbL@)sUT9PTqQL zfFPL#^IENm{+R9SFQb1vG}#*Nazr%yX;$`1!yi+wT{X zcN8VGJJt8@%UfL^UDX6ixgMND5~gIn_gocOO{9rfP5cZn*+^-(-E!v- zs_Lu$7zlPEin3y=A7|;KqAyb>yXSp{V z0(`|SZ5Id{t8V8^NtAzuOlKWMp+;k+I_+9Gfv$0D=t|@KecX$49_UMi_#(V({0~QU z@ufPiJyNx+EWw1P%0V?UA--(JuoQk0`JrvJC_?Iq7iGMb8s~$~DI7K5VdMvz^)Rz^ zVqH;k$mISv(6!mX;WM-Jr>4h~tG7!{AtdQUm>qTSV&a+8>l@@sA1Fqt zKBQ&y*L**fzM#Vh21NAlHwS%L*cp|+oWD4KG~tw9B>3{%W^MPvslj=7{=weC3&KL( zUDsKfuKcMPT$L38+2zg77Kf_{S1cUsS}S|C7U4|(N=dR(vbk(&k@t`zK>Up8@88uQ zT|XWeoSc>(xJVZ2@@@vW+4mXTIFdU1_Jb`qayPIN_oAD7_*}L^@cg1)_owT@-j^4I z+0YS)Gl95jV^q%duP>Qs8V)pWTHkFu@($8dKF$uY$SksL7oF?e8=P@^`7Ypi|CCP! zu0=?pF%p%MbR-urP(3kH-h25byJDtU7Qc0@l}ZCBZEzzKWe29_?GNo!p<7SHnj&g% zw;Zx}%@j7qS+Qb zNQ2d2uxsw~Z;7Dxb~?GSB>u_AW;Vj#&aI2C5toylWYAw7#^Jm^y3T)=#1o_^|KRkk zOx&q*6Ehs=UA$W8W9O#G(1?TIyvF{-D%g5t%zfPYnEj6{F80{y@R`eD`?71z(bO?| z-?*r2bdk0ZM|AU=cf3{bc`yaa5%xui+751TzwZE)6{(Dl_=O2uPr^#4sU`u-9mD)b2?jxVyVsk)p-j-5rV+cZc8GGY5%N`)qq>0%lm8H1uS zrdQ3<#fnm=+YqTy#qn+McW{6Nihq7Z%e?^;q5A?s$#eedqJriK_0fw%PWwIn2(QJCG|R zma%s1hZS$wg$RPFr;`@@oHqFnTgJs^f|N}7y)BROi2PG7Z`I^f3&-^cBK>#d0vX|3BeajwXf_ z)j5U~=eY+eVY^!~Xi7h8=*EXHwV9nP};_?~c{#{?CH^oz@I@oeyA*pCWq zw2e#6in8t6VUg~3Fa&usGc3uUi`HwI8+pFV13Xc|MXc`&C~b;JS1rj~QNxgMew1nB z4D7_d;*5Jbetta2!F8;T+(Ah#V>?ty2MFS6m6!<7mjssNi9{{Jd6I@mONNHezENXl zm{#X~@>eZ-wi)$l+aKLnZ2t9gmg+|&I7jf48W7C)9)&jHBVmI}LsCPnYKEx&wW^VE zk_3I6Gz;n!XV3;6E?$whGo9~QBJ*mamzN?lAAM2Z4##_ND)HcXvtF(%>8NKz?UEE7 z?rLi929wAH*}Huek?7#OH9uDR4r4^!8 z!+gxw8yooRJ9R2gT&#u1ip(KfX%ZPD1Itr{km7v6<~ij(mB;Bl>MGf)sg^~Y0&dEE z#jWUQy1G&(W2h^+1%V_jB8^WDOj>ccmDoPAwDo4W>ZW)X17o$#|!LpDQEjR{+@%F;CNwQpbc zB&8N0M*~3Y(j31o2D+X~GVwA~fpbLt){>Oy*EQ|ti6O=2AeMa0bkTZp=5}8qH9C+Q z)!f4wQMt#uQe08ZqjVMvz>g*=u!sV=m|~a>$aBCW%zE4~9)Vkv!7nZN>}OGF7M&&U z$9Ixf(P|^!>m1XHitm*4XvJ}eeQ`7@bP=-I+erOa?-J-(`Zm$} zF<@@r4$ienzdE>v(!MbukitTUz5knc2hpuUPVoh~^3=n&#$4MsQ>|%MXh%Wyw3;Lc;%mI@i9@)W#Xg-2d^JJUX z&~w&rf_aYhCEa*bztc-(zwJ3V?3Zdid|1Z^p{R#y0mB@CKH^fF0JdLmoAQ!CBD!aA zH(hG-<9ec^3IF^y>>_1~G;E-+nJ_m*CrhTt#>(o-<`u^eA;|X61@utYA?h#B8<`&9 zlOihJ2^g-wYZsEa3g!N2YrnuitM(`ixg2I^P2DLf^5|iizv$Ndw|5~I+5+os3<|WQ zNe`R0z-@R^Gpv|v8kDp{=x=PpkL+5!`Ip{bk#dPaVEL;dW&5qXS|7ZG*Zh}2%bO^sQ zRZp&#l~(^~BpJ^=RO5lj(Vs_7TB}3bJ}{CZatr-DylRxD)fKHJ*}4Y$@8uzmlTdSNLC-=#x*qinNNdsti|E&#<_>gdGl#&xN0zplKnw zc{7i+`iFZT@HicD(p39DwfCUBR%9fzNdNE&BEEMS-5-UA4vVkY zK8b37zeRds)B-+MadU0|0jB$KV1lk`XDa7dZYcpm%r4=?U?K``7nh!}!PiG*Dl}S1@NdjmWipaWmOme@#>Sqa> zU7c~ErR-P1Z_^JhP0W3JSpY4-V#yp;zVTmiSl|faj&}H;tS?d((}FQ+=wzv}{tTo~ zSB@lFKq)|wC+#;&@HJ$`?)Wnk;~;gax{mFb%n8?lxcUD)j&Mg-E5XXH!BSd8e!WDn zRVvQZ_B(VxbNp^And`q1mup(`;z`zVtlpmYvPp%I@`{uYGwJ&v2v3MCC=Se`n2DN* z=F=rA@$IJLJtn^aqADzbm+5v*pT%TYiU7(2eU&3^G_pt`^)j$_GsaUlAHP@ok4c0S z4j4Tz+VcwVA%HES+4{n@USMIhH7XMB316QN8I3_)jbmt(^cAD34uk>VjP3WBEa2%T5 z?e9T7(kD6id^PQe`Vwc8v-d_83T?Ebb0P6OE_p43-*cEc)U|!Ci6Jy-lH-dV5mpRS z;JH1zTW>Q32jb&{`XG0CTTicx0NcQK=>U;^K9CS=QsVcujRm0U_;VWtV(sC+*(5p- z_BHjg2L$M%nt%(4>r;C}7^Vn1fr4%v`BM@;n&3TgCQySCP`X|z>FX;H)vH2R_WPX{ zz+or$2Q}q62=ZbZ5>p)J+V6bXRDmYRi;iO<>DC)f=-DtvFI{(X;CA-TJoKon7MDn) zHGDYZGq#X-8J#32uaN?fMh?b<6J*3HIkb{ z!q>07-hB&0EF`ZFU&K4g=Ti(~4w)=IjksgKvRFFjRph))2}uY^3`q*9I|@j3%19UJ zi`y8!_<_t{+0z$Snh!C}Z4V=j{eUp|yO0_oKJl%vgG5z?EotRu-$%uzt9v%iiISs$ z%fS*sEj$p7d-EVzQ@UWCc^iWwkQ~x!9{XkY`Tu&-xT|lt`FHHZfO67xd=Szap|3U92aA!?O1 zheL&W8p?FKNvPt*EV- zty)SrPzD8-1<(p*Zck)|O7$wXrB~>8Z&8V|lEaYOSVlF#K`>cm6m~n30zXefVzM2V;gS5NNcITZli$)d{hZ z$u*se_D@8bWq#j5)Rm%qLe+MoaQUeDG^+lj=a`Z!j5vhLHk>Ipj|%CHxM}Q!t=`6% z5J%#^e+C9N6c)i}655NIiKfND`I}f$3xAF8USJfVFP7vVa%|eW?8BYQKFiJc)(_+Dd_GUGu1kc?Sw?w4 zte+9lcOQw`0C`bE1Xk*z36A7i|In_Z$4yQ1p9 zXIkrsPieLFTyy+rrZocx7%OM!g(sDZnsUHWD~r41(iI;^sBc88loByuk3@=S+&gzm zzG~*qH%60Hc+wdvNW9um7M6@NORc6DdzQV0!1I@SOei|YB35Rx{M9s=MC3HB`2&g_ zW=(KtatzVmP=Dp|r>(1X-T`ewl3HbE>2FV)s6OU0>%SoybQqI=WGlOAn)Jdh+h+e} z*iMnlg=R5Zy(a{8%tVm!cM|=KI_M3IrqJx4H$1PP4-*DXNg)VOht<7&ck6;0$JX=juH0!J$fGM`N)ijC;R(Z?3t%tvk<5f1l_Hx z+%aFtq-B`n&ZG_dB+By2)C73oGKsFSY>$;4UZ2dFjIVF=71H)VOQUYB*i3KI3$i&pNg|u#aTrTTm@L z1+3toJ-o7oq;h%>I(*L>^RYqP%|OiGAh+*+;(fe?H zJy0=(cL~&mOmaQ5N&C=kU&8D|-D9wF1*kLaK$g0;R}+@+G_v(U8;Pxlwm2aR+9C)x zm^Ay8q2u)3-E+{^*JQdR63{2lWpRW2AdP@7Msf&^&7BTDBGi|6WR>T6+Jca)w$FaZ z-iO&`R)@<|7anx2$tEW!8fN{r`W2Nn_IuzCWC{~LeHJ8|W(EVEm(D(~RXyqusl&*# zC)A(G&I|7ZM*oatC1+X|l15Qb61IUw{x)1opM9lxmT$T16>cf|j@@zE9Ze{y?}!7O z#SF0FI=*y29>u*%L8dMm%pdJ^Foat#jnhdjzooCGK#xwb=x&4ZF=#Tor`qLb*Z1Ow zo{~>;Ku#&NRa{@@^g3~!M6auYOT2e*|Irx&W5)YM{N_b+1igeVA`3IRRo9lVzX;h%`N94c2r_U10SXKEC^2_G3AKv)G{udqY~DTUCV!wU*5NmISYb z0S2_=#5n0cZ4=8>yKD>6#~N|5GXtCmM?$(s!Gn&}XqJ~{oJNdt0Ljmf3i2Pb>0s!X zsyIXQhg{JdTuYjY8~ZF;PybYS-Prtl61p(Y#=mMR)!BdpI1rWfOob zT~&5Eck1aXD}_AcB3_g@bWh9a@PS5sB<6bH=`CNzF~-kDDK2(;sM}Jz<2NQMgiwL* z<9`hdC_o$HSpX$dy55hz)UQ<`x*xzK>08M6_I6@VR??%sW45*wR_eg6Ne$`mk?X<- zFEwI7U!X6QGR&eL=GOzvGP(}L z|8Ruo|C!D$+MHdVroGT(8_ozbCr}y3?^mu2e#ZX!JPtK+`?+zps*rl|mwfCy-sjq{ ze2!D8ytcauy1>x8LmY=Ei?^$xA*mCFzZ&|$4t*Sy2J@@@{fU!65nP5L&*>LQR982N zXN2d)l>QBTtQlCJDz`W{LQH{YOhMZ#O}fn2mzBL?kc9fbk^SLymYyqQ9fd8?JhXq@ zpFJ>a&=}rvu){j>^seKL0ZIfH-j7SSXDOz2ZafXvQV>mfI;ac&Bs^Co?pO*;j<1`+ z_LI43#ida`P8=8isC!@B7L-m9#3a?(t<%Tl{PsOLEDZf0_z9oSaPmXnT{EF`dysL1 zQ$Zjlve}vA5r*ZBkvafbA=ZrH4`(}cC9zkwgJS0~0g3mP$?=+uD%N~w5u4%@raSvH zq3gQs|LDF9p=|67qD1d3N{kmj1ibP8SI;dK*;e!?eD}ASrSGEIl^s+?fSP>y-(jq& zomz1OD)ebvnRDUAN>#neL!G;4gHE|_;Zv35igN z19B?4=HLC@ubJK;Y811$q~D80>Knz|K<|3`OR0)&QNRql(f9$5)M>IhEx?a3!}nV< z8mU7lL+K2b)0_u$!>y~HnxoUtz!=C!ou3SmG`W=v(4cl$)-i-gi1O0ja9 zo6iixEu8IqUtbJkC3>+91;;L(2BcGm^YuL=_eYouo-gxrV>UyAwdBnAG}B&1734l$ zj(WsYD1Vg92SW2!Yrlsvc2|F>0s{b@_GX0-a2oF*zb1CNL@|2%O(A5aIu<)yYMpSqM#GIzb_SwrnvR zuSMKg`ABd;y2XMkIZ8v$9d9SA33qVrUaSYMWPW(Ulb*0naHX_6;pUh<=U_E@@M|j_ zQITFFy8hQxBzOfBO?iyH1U57fudPACUln(ujfFGsPN_}O205}b@%q|CLNGmE+5YGW zSHDW=v zt5_0tgTUHT1BC_#zsyOTtlKS;8y`L!jcx8l9$>(e#7EDiv0BAPE?o-VlrYQF^Ju2|jij})B5B*~ePB&; z54u5O;J}mzVfb&DaQrH{V4S6ER3_rG8QRB_v{whTo@Y+u5lBXbQP{wBqW5>5&z4`E zaBZdEXc`G*ks@c{KN+>M% zl+68+IY>@AQxhY>l#aGn7SIv}MNP)48|=;De8Hi!T*uAg;~gN!$VxJfU$Yf9)i(m2 zFM{8ZyX3!ifRl$JB=K{?N5*9fJm_O*klY7~B_`*L)FS-8=Fj|J!Nqh9(Nh=6(L^9m ze2a8J(V45Jvo7)Nv`&6ZpDMN{BpP~PA*c>EC&btNe*9SHe23}wcY-R=e)x1^u_(uz zsp+iL%|Zy|y`ilEtii=5pUV<~&nReCSS7GXFnsO87$O}99#7A;Z|MCp%@8wCqu=ot zrxhRNXukfpkmq$R)~`e*_pfjxlvR8SY=}AnOBCY9Y%JT!MxilQ2RLB3F;?ihM4;Q! z6LG<=;@hcjISBJ{o^9euKuC2wFk{Cy+T&33$Boupg%sqEc80ve2n0KAKBZWftft2w z2;P<~>e&l}YBJHF8qbQ#EQC+s6NWt56@nz~KK`C$l6SNDF zo7M%P>+w#o>*cy}rjNpZZ7zXz>T!L0S{gL{65bsn(ieu*QXp}KA3R2|L6%ER`!wi8 zLfT|%eawyrrMuKI)pKQ%1m!SvL@aMEr-YqUI7Q^^@q-yY5+w=fX0o-6^^!m1?fRCp zKxS?W1#8_c@xQ7^1kgTfn{Lw6xJA_=|BdV3pnhU*H~lRiCO?V2y~##RZW-!N6}Oaw z-ipXIyGl#*EL0Q!2BS6YBZ=$r*AJ&)o8W{dL#act4l1EL4ggTC25m79aMDu z6>d1CchA|i9IiW7gI1!L_X;-*ujM7JDe>v0AWPXTexJgMv-VOC<7kno=;jC3bjz?~ zOr8|@9t4Y)QgaoN>6EBsIh{<9TlWAoW0>HFML>uPVHcSvD0Y`A{}TO0m6phk;toA7r;<(k&G+hcSZ01(~pv zI0y{|x!xf~Hi_nc%wQJDFJd2tP`N+Q#j5Dfyct8?i+LD4n6d2&4i$GMh@d{&ISH9M zNkjFC;rf8KQKj>|V-F8=TyKYQSe;(xf*iL6D7Ig2*xOz#DDNx$2`MZC6bw59J4Z-R z?=2EwA(LvZo!vNrM0eV3hys$G^jT~f)I0hDwvn41FA%rloty1->~1E@G}esSWZlMW$BQ{H?03Lg3g&cKB8D=AEWi zQW71pnIs5>6pM2#CTD6fp9J@_WGKZ2BUs3pQ3&=0P+w{QpX;K-JchE-`qbSo>F*J* z5NYPerqO-!iUI2YFbfK7&}fGi%=PFn zbCt58p^})8o5FZT?Se@#{}Y{N#G^KdBMnUwXi@<4Zs~yXZ)0YIK`4r$?*Xp*s59ad zL}rQPJ8h6Zy4}BXE4&d@O9XFhKQ18{Y9bxcPi6eXxA|`#-)FLTuOY!`6pZThSrVUK z{Y7>^2HlVw=6(FgAS6Nj6GOX#3nx$JG{u-rE|d*ghQ$qIUzY6ArDyniO3au)MRFc3SR`E&`4Z*N#d@#XT?GDB>dJIQp^`At0Vwn<4?obElYPV zZPA3#*L=-(Y8bIw$@5lZIwT7w8uA1OrE-NAF6&ezQEa1W3YvFv^n{cU;oISX{p z$oJX$Q&CTSg78AEU~*xSI`R})nj`*;HWlTm6on(YbSNq4(UDUKb|J0_=x71^UGvhR z>cE_gzSM03I^=(q$U&U{s0$bnH-eW?#O}bF>5q#3HLtCL=iYl_7j+*-{81nKp`3L5 zn8JB@Re)30t18s|F0yJKqv}tIR?wFB+OYd)oF-`1tFevAl2>VPu=t>p2t+YS&_e^b zZz6O7>5L*Ynx!`yAc8FTw${Y*7-avqZ88OTAk%GBNy1Bf5<2VCCM^^fKXv8Wm8x)B z{;<$uC;i=M-Y}aVG@P|;gyai#DR!C2wT|~bE&N}Ub3mE}8}!r6 zX{@ z9v+8j=Ua0hB;p%F>cSnfgG*K&O<1Rvq;L7q%Y_me-nu8pUir>!KT0DJ`?tp#%JN)& zf7gJy3dlsRm5hFpo5>g`l%m0w!a|#6U($-75RDSjO2jZhN^V@W3fwU^?hjA-Q^KVk zb>aR?FW%kY0RL=+CL&fb>J3KRWfVlPHGJ@g*}2ms?*aZUR!FHB%e}TgZ(N#8O*Z1w z7Ea-e#2;07Wgfk@S#M8u{@H#LllZUWz@}6D z4O*3@(TJnaITPN$t{yb1>Evo}ti|iHjhsM$83qmE|rmtSPOwY9Y;py5YYv#5P`darC>}fjMe7WO!95 z$K9S1-#asy*PF20G2 zJ8@9hfW*%VRS3xqyh;;BqF$%r(XSStaHef)ea=odBNI==GqiMV% zmN++CeB`UdkI3i?(Wb*@G=hQ;~k-EO;Ssu6pN8f-v zVTgkHUuu7({KI&2Cadt|s^Egy2-}q@a6mFLr4#Rq9*$Ukyd=>GhLR3pNM9+Se6*kn zsc(n!lfp)$9#E{WCPrau1E*H^{Jh6&ONe50W*@%7gt^nGgB&{D*j_gryi1^{IhXl? z(i*c%-rOIghCp3*?UKttk2h=z0(Ap^993%~HY9l1u-8 z5E_NXJ#7OHJiUJj4dDJyoNXA^`(gDho)tD1cM6 z8bo-sc$cOhrc-wHF`Lg+soHZ_#QCN+>)zfTd6rVxhKO6wQ=+m1ktP=v1r%H0UXffU z3xLxt=%AASmv)pmm4k6o;ZEN-l12fq$6gxHBX=B=Id^SJj;q09{BiWfqaegRYnbYU~~^v9gfy~qW>Xh z94f8&|7eg6s%g;h-WEc`4I@M=hVBS5?Fh#Ej0wb>A_lH92j5#oq%nHdN&i5@T&`l= zO?Y=bO^ElYNfLIMGz%|??OzWTjK`_)U4O`d%yR-mJ8zDyAAd#I$3#MYXyOoSFpF02ST5rV3U=JFA76iOs^j;RW6%=VN+RzPwmkdN zS<28GtoWfvr6&0IJGC);uit8KpAs7u%J9hT;+27ROM%z3vFRF$m-HP4yQq?wJC)$} z0eom5{EFiBDZwNjQPc2J1<^f{85)uJICR0E+%oMLGy@Jbo*_Sedj0A)q^08ew*|&+ zb3)*?!4A6aT$LVZ5t5fxYyO4v@Z@d^bt=mLEEmEP9j^@-I-}p>)6hoKNrb>&Gei46 zy`zOQws=Gu0$AGl)4-Y`s0Qah+M$KTeKmq45Ae8JFiC`th}dj3wVhL@8May*A>>_I zG)W@}TZA0XBKGR@%XrV*pV_m;-^Y!ys2{cTgOFCS7 zfpdI(YGncGbU0T3;O2T4y|JU<6^jq`86f%sT+;SxWz=WFaWvw@x_(b_(tyv)z?#S~ zTzr`jMlep|V=&0nCo(`3grWpL%C47)smL(W%0+Qx2$a@|az7k7O~+Vo;!rc0&||H) z7?;-cef1Z;GH@OGqiL%ze@J8opIf6N9;^FO+Gq461mIv3_Y_cpsP6`_8*j0Nbc^%?D?8nu7PVUj`T#Htas$=|XLa>zLZM(jW z$4kT%c*R+KCuTRaqB$UP_2?J0)S8o%o98HgL7V;ivY;tNJEjt z{7=xpqSUk{a({w8E!?!tX@y|3YiTGO3;Lv>v5cZT@g37z!IYQ3VPzuf3S7AAPm^a# z`<|h%t*@sGSieVA9A#FUeIl(}fM;);Vn(2|1mEe|bl1R^0xNH{@Txj;<^I?CNiLy% z0T8*2N>gbwWU7dff&Z%(Rb)J$(O@9-(JXTqa{Cd&(Efro@1W^Ioj9=6qa-x zV{;1X&PQ%msPcRvnMuRV1i8|1N9)RDDO>!g&Q-H80_W|I}Z)-B*_ewVmyf)h)k@_Bw&wZwRjGYGF#v^2AuK=;EO z0Z1`80$pFZ@->{Ao3j!^$&UUN19l2HaH0;kUN~<@#Mx#Rf_XHW0Qo{$@)FtIK z`-TK+7UUr~C$&VE+i|Z5p=Fl4XfSwx87@^kga&}&+Q|Y z%a32lzLlEEbwWCiHMiA@9#v_{2usI3SFXcXnpe03v3tle?!f7~sA>ezA&L$gv*I-> z0zlt+3{H%7-HO3+*Rh4P$q~f0(xqNt66#KE_e(yoyEUS_2^;WsI z0VA-1Zi4kmqamn+I*{=d#ETAG!gG9qW$d|oJKw?<((4pKP6EN@Ehw1Spg?9n@cx4q zXx3c$NrlP$Ux@@c9haesM_R0kz*m%J5Pf{W4p}@mbz;Q+;C!53v%6jq`;?_>r~pK8*sSb)SKpE zj!xaKqUQI)5n9<6kaMj+OCJ;4!0Rb^77a%MUEMOaZ>jL$;(oV+V7hqrd8yz`$qXr@ zO}BS%1fAm4Zt@9xW+Lj8;#8B$PFTO2BxAK+RJOz&m3b6FTRmR2{85n6>^bd2(7 zwc>*XvK-$;!WLXqNoxRATzNQ^Vc0RdBK4NzHwc`n?p?E27l-xbdly)USn9PcWIE}) z4!hRZ>S&)nN8BNpzQ2*rBwuhy!b<61GN6h}9)h_Ml=ppKE#z(z~Hc@=5- zvWjAu<)OUm#lg^^_8TEw`m_s-!BN~gzeM}a) zjF>FwH(RPVfrmYKLQc-Qx3XO#S=21=1_9@3N=uJ(KJJZ~oK3$YJD!;RfMJETXdYG=YOK?3Qvys-Tyn zG-uE$#@7*`lOkTZlQt?MDf%oU&nWs(-@`caOp4 z`LmJJfX-15k!(}6KOox0_+4gN9=At3q8D$-8mQUM6Sp0{^cWJi%omyX*z1z>@>oer zIbyx;#JA%%=@kgOcy?=69`E;y|0c&9yiwHbq+3BZL;W=Iw=B6sOujQisL)8dH>rnP z-QD~c@gT}`ic6&50jUI5mRzbAH$H@shffJ~*9oDTH>1r;e8+cobB#p3s7560#F=xJF^R1@7vL=NEFr;b>bocxNMt^!P^Dt83dGZXG)w6* z&z4j;v(CAhVV_qzFVz#;Vu!cRk7*eAZ&P?SfEBJ72VLjqoz{>a+JD~u;u)`fZ`!WY z*_>ga<=>3g*&mJzdV{Zf*Hh7W7Bee_H1wfQOaE7Tf*dVijLbTlIkMMigDM|9F9m1T zV|v`#_)tkWD0qYt^hHFS!c&K?JJSQb!(@dLotS8~=OKjn%Fkq(*Zw>8o2feXIAC^=kA^yn zwpCL9qh$=UJzWs}_)^UrW=^+3u{~m(*<#}8=%j=DI?q*H$L)3}_JBC&kI%H$?r<<% zHKsobKXyc>>rwgyx%aEk0pSVyTA(2u(ApNNBYw+13~RoSHG@zkSxc0~Wf~&WMuyR&}_9F|k)9kO{)0ZW|509D6jrHD3J=KFIa9!2QuE+)m zu%bCh{#@k2HPO!If4`Dht68Gc#3_$4F+9{hL^r>6TBVKXSC})uw+@S259UiWgc!(iwJ9+4 z;?c2;RtztE5E?Z${vp&0DC8q;Csw2$3R3yGSdA7dm5*_-ae>_VKzJ<;RtXaKab2sC^@S#8URnXUaa)E43AuQ<@a=7R8 zvcHT>((`0(${jg#F~4V>o;O|f{R(`;Y-=fpY@9<}VDl$YGao#rg82Px=Q}*%tdgw> zTKmI_3tS2K@@|ddFlPt%{>D{tXnAKNUnVTJkS6eVi2TOnO0}@V+2Vp;4Bp;D%C!3! zQ6-vz^7i`=Sd-K#mq=tD=gW=aDuT}X_FmB1cr=|PK^q|C6^9?r_KTdmvIrMi{om|C*WFLb5_hhor--}Z1t>l~Dn+4ROFkf;CZMXIwNGqqy+n)7w)mK9NE!3$g)ShF)3~co>B|{AzrF`(R9^u(&P6+K#Utex?$6 zzHY{)xKx`dnWVJbz{*1T&80s&ToPz~{vbi_-Xo>MOWs^=r}atsbm_|q5Iqz0`H8m^NRpxWG)nx$~$KA$oB}T+Q^7x#1i9|0;r)0Ep z`=-o|x~h!EejO4_&3WT+>@-(Jr54aC9yU)blRqp(Ui{lAAxZqT^^a10lH83)1d3si zq+_v9+m}4daONBQNu$EgxHb{9NPF#eOiK^tJDQ|5RtXAP&Mzg1y9?iSvb#>+V+=(p z@vi39=mz;Bu~aOLQ{N(X3mVByN5Mor^Xk(=2-};jCSP%WKjX$db^6vMr$!g9w|ttG zNnJoCP~_*^qqyf>;o>$wwB}3d%(`vfbLS@yd0)aRUGB{|ja4N2H!Caf*!s;&5M(b| z=*Y>TT=663px!178Iyr8B8zC7Ubp)5w8(@mM#~$1((?>Gjp;phc|=d^zTAGHKWTYN zvKW)fO%bGEEfSFX9!@+>FQNH+fbMrOKCL(ePhx8-MQ?vTHWAzBkNNrsvLL@mXq4aWychS&o?VRf#rE6kC+$$+&hc{5Ne&rE zKG|$k`5GkOiPLU(lSo^{Q#V7u0_lhrk<7lbL3+cBEOOd#XAriVQ@+3@qb}HTuxDN^ zv)x~#Gl4^0lq>p%{FmcY(?u8ya3Ob@ZAm+CMJb$UAy`5y=AFaNgH_Z;QYHA=<Los^P4615`ATU{7m+Ws9*b#7eE9VF@ST`9htx%yTH(kV3I7kb02<`cmiAxi=ap zua~WEG}`!eGE}=q%y=89y43C4XRnVW=FdjNVxz7JFGwdm?bP{NF+*)u%aau!f4++P z?!4AP)CnETRq)m?R_BW^@s)du_o-^z|EMGsq5o{*a}_fvqV6DE*%tI>di|fTDWCX| z`_+7q7?x4@{q~2^*!9RR2biZSye6`b`sB(H^Zb6ovX9b@#D5(biRodW_yZvZ)tyqf z1amz!T**d2(NMWf>>o;VtSd2*^y1uA|H)@U3}I_*ncL-%gRjGvda-)jXDud|L2+jT zQbA#bKL@)*dt31@{%~_fx&6_tQ7;VV^JqRCA#iQppUi)0bkRz3Ay2#eWQvmCG#RY{ zYm$~BtG|)0h0`_~!?xoc!vOPSL?>-ebef z!i7>Tf;{u=k~zl)n!=Y5Fz!w)sV$;dzmme`^|TmmsbL%Zcu> zZ)H4KiklB{_n7KziFNl1|IClB zP%IL<_pAOBU`}y5T-Ikjvj@Y-r)eiG6>!pjOyTDVwH&{rSD75)Q2KZ-JFsaleEw3; z`cP1`%VM!O=86iIRCBvT6WU2sy9m$9AKyGQVhJnk;S--&}4|e zN diff --git a/wear/src/main/res/values-night/themes.xml b/wear/src/main/res/values-night/themes.xml deleted file mode 100644 index ad19c38e..00000000 --- a/wear/src/main/res/values-night/themes.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - diff --git a/wear/src/main/res/values-round/strings.xml b/wear/src/main/res/values-round/strings.xml deleted file mode 100644 index 62eacd26..00000000 --- a/wear/src/main/res/values-round/strings.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - Hello Round World! - diff --git a/wear/src/main/res/values/colors.xml b/wear/src/main/res/values/colors.xml deleted file mode 100644 index a7c719f0..00000000 --- a/wear/src/main/res/values/colors.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - #FFBB86FC - #FF6200EE - #FF3700B3 - #FF03DAC5 - #FF018786 - #FF000000 - #FFFFFFFF - diff --git a/wear/src/main/res/values/dimens.xml b/wear/src/main/res/values/dimens.xml deleted file mode 100644 index 2e76f3e3..00000000 --- a/wear/src/main/res/values/dimens.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - 0dp - - - 5dp - diff --git a/wear/src/main/res/values/strings.xml b/wear/src/main/res/values/strings.xml deleted file mode 100644 index bbaabade..00000000 --- a/wear/src/main/res/values/strings.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - Szkolny.eu - - Hello Square World! - diff --git a/wear/src/main/res/values/themes.xml b/wear/src/main/res/values/themes.xml deleted file mode 100644 index 58cc0c22..00000000 --- a/wear/src/main/res/values/themes.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - diff --git a/wear/src/test/java/pl/szczodrzynski/edziennik/ExampleUnitTest.kt b/wear/src/test/java/pl/szczodrzynski/edziennik/ExampleUnitTest.kt deleted file mode 100644 index affae81c..00000000 --- a/wear/src/test/java/pl/szczodrzynski/edziennik/ExampleUnitTest.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) Kacper Ziubryniewicz 2020-9-17 - */ - -package pl.szczodrzynski.edziennik - -import org.junit.Assert.assertEquals -import org.junit.Test - -/** - * Example local unit test, which will execute on the development machine (host). - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -class ExampleUnitTest { - @Test - fun addition_isCorrect() { - assertEquals(4, 2 + 2) - } -} From b6d625a1fc50f819a06d6756787109ffa777d92d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 21 Mar 2021 21:01:28 +0100 Subject: [PATCH 012/113] [Gradle] Update most libraries. Rearrange dependencies. --- app/build.gradle | 216 +++++++----------- .../ui/dialogs/RegisterUnavailableDialog.kt | 2 +- .../edziennik/ui/dialogs/day/DayDialog.kt | 6 +- .../ui/dialogs/event/EventManualDialog.kt | 2 +- .../ui/modules/feedback/FeedbackFragment.kt | 20 +- .../home/cards/HomeAvailabilityCard.kt | 2 +- .../ui/modules/login/LoginPrizeFragment.kt | 2 +- .../login/viewholder/PlatformViewHolder.kt | 2 +- build.gradle | 50 +--- 9 files changed, 103 insertions(+), 199 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 47d1b31b..466d538a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,21 +1,21 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-kapt' -apply plugin: 'kotlin-android-extensions' apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.firebase.crashlytics' android { - signingConfigs { - } compileSdkVersion setup.compileSdk + defaultConfig { applicationId 'pl.szczodrzynski.edziennik' minSdkVersion setup.minSdk targetSdkVersion setup.targetSdk + versionCode release.versionCode versionName release.versionName - multiDexEnabled true + + multiDexEnabled = true externalNativeBuild { cmake { @@ -28,41 +28,35 @@ android { variant.outputs.all { if (variant.buildType.name == "release") { outputFileName = "Edziennik_" + defaultConfig.versionName + ".apk" - } else if (variant.buildType.name == "debugMinify") { - outputFileName = "Edziennik_" + defaultConfig.versionName + "_debugMinify.apk" } else { outputFileName = "Edziennik_" + defaultConfig.versionName + "_debug.apk" } } } debug { - minifyEnabled false + minifyEnabled = false } release { - minifyEnabled true - shrinkResources true + minifyEnabled = true + shrinkResources = true proguardFiles getDefaultProguardFile('proguard-android.txt') proguardFiles fileTree('proguard').asList().toArray() } } - dependencies { - implementation "com.google.firebase:firebase-core:${versions.firebase}" - } defaultConfig { vectorDrawables.useSupportLibrary = true } lintOptions { - checkReleaseBuilds false + checkReleaseBuilds = false } buildFeatures { dataBinding = true + viewBinding = true } compileOptions { - coreLibraryDesugaringEnabled true - sourceCompatibility '1.8' - targetCompatibility '1.8' - } - productFlavors { + coreLibraryDesugaringEnabled = true + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = "1.8" @@ -76,137 +70,97 @@ android { version "3.10.2" } } - ndkVersion '21.3.6528147' } -/*task finalizeBundleDebug(type: Copy) { - from("debug/debug") - include "app.aab" - destinationDir file("debug/debug") - rename "app.aab", "Edziennik_debug.aab" -} - -// it finalizes :bundleRelease -task finalizeBundleRelease(type: Copy) { - from("release/release") - include "app.aab" - destinationDir file("release/release") - rename "app.aab", "Edziennik_${android.defaultConfig.versionCode}.aab" -}*/ -/* -// this adds the above two tasks -tasks.whenTaskAdded { task -> - if (task.name == "bundleDebug") { - task.finalizedBy finalizeBundleDebug - } else if (task.name == "bundleRelease") { - task.finalizedBy finalizeBundleRelease - } -}*/ - dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') - coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.1' + // Language cores + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5" - kapt "androidx.room:room-compiler:${versions.room}" - debugImplementation "com.amitshekhar.android:debug-db:1.0.5" + // Android Jetpack + implementation "androidx.appcompat:appcompat:1.2.0" + implementation "androidx.cardview:cardview:1.0.0" + implementation "androidx.constraintlayout:constraintlayout:2.0.4" + implementation "androidx.core:core-ktx:1.3.2" + implementation "androidx.gridlayout:gridlayout:1.0.0" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.0" + implementation "androidx.navigation:navigation-fragment-ktx:2.3.4" + implementation "androidx.recyclerview:recyclerview:1.1.0" + implementation "androidx.room:room-runtime:2.2.6" + implementation "androidx.work:work-runtime-ktx:2.5.0" + kapt "androidx.room:room-compiler:2.2.6" - implementation "android.arch.navigation:navigation-fragment-ktx:${versions.navigationFragment}" - implementation "androidx.appcompat:appcompat:${versions.appcompat}" - implementation "androidx.cardview:cardview:${versions.cardView}" - implementation "androidx.constraintlayout:constraintlayout:${versions.constraintLayout}" - implementation "androidx.core:core-ktx:${versions.ktx}" - implementation "androidx.gridlayout:gridlayout:${versions.gridLayout}" - implementation "androidx.legacy:legacy-support-v4:${versions.legacy}" - implementation "androidx.lifecycle:lifecycle-livedata-ktx:${versions.lifecycle}" - implementation "androidx.recyclerview:recyclerview:${versions.recyclerView}" - implementation "androidx.room:room-runtime:${versions.room}" - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${versions.kotlin}" + // Google design libs + implementation "com.google.android.material:material:1.3.0" + implementation "com.google.android:flexbox:2.0.1" - implementation "com.google.android.gms:play-services-wearable:${versions.play_services}" - implementation "com.google.android.material:material:${versions.material}" - implementation "com.google.firebase:firebase-messaging:${versions.firebasemessaging}" + // Play Services/Firebase + implementation "com.google.android.gms:play-services-wearable:17.0.0" + implementation "com.google.firebase:firebase-core:18.0.2" + implementation "com.google.firebase:firebase-crashlytics:17.4.0" + implementation "com.google.firebase:firebase-messaging:20.1.3" - implementation "pl.szczodrzynski:NavLib:v0.7.0" - implementation "com.mikepenz:iconics-views:${versions.iconics}" - implementation "com.mikepenz:community-material-typeface:${versions.font_cmd}@aar" - - implementation "com.afollestad.material-dialogs:commons:${versions.materialdialogs}" - implementation "com.afollestad.material-dialogs:core:${versions.materialdialogs}" - - implementation "cat.ereza:customactivityoncrash:2.2.0" - implementation "com.applandeo:material-calendar-view:1.5.0" - implementation 'com.google.firebase:firebase-crashlytics:17.3.1' - implementation "com.daimajia.swipelayout:library:1.2.0@aar" - implementation "com.evernote:android-job:1.2.6" - implementation "com.github.antonKozyriatskyi:CircularProgressIndicator:1.2.2" - implementation "com.github.bassaer:chatmessageview:2.0.1" - implementation("com.github.ozodrukh:CircularReveal:2.0.1@aar") {transitive = true} - implementation "com.heinrichreimersoftware:material-intro:1.5.8" // do not update - implementation "com.jaredrummler:colorpicker:1.0.2" - implementation("com.squareup.okhttp3:okhttp") { - version { - strictly "3.12.13" - } - } - implementation "com.theartofdev.edmodo:android-image-cropper:2.8.0" // do not update - implementation "com.wdullaer:materialdatetimepicker:4.1.2" - implementation "com.yuyh.json:jsonviewer:1.0.6" - implementation "me.dm7.barcodescanner:zxing:1.9.8" - implementation "me.grantland:autofittextview:0.2.1" - implementation "me.leolin:ShortcutBadger:1.1.22@aar" - implementation "org.greenrobot:eventbus:3.1.1" - implementation "org.jsoup:jsoup:1.12.1" - implementation "pl.droidsonroids.gif:android-gif-drawable:1.2.15" - implementation "uk.co.samuelwall:material-tap-target-prompt:2.14.0" + // OkHttp, Retrofit, Gson, Jsoup + implementation("com.squareup.okhttp3:okhttp") { version { strictly "3.12.13" } } + implementation "com.squareup.retrofit2:retrofit:2.9.0" + implementation "com.squareup.retrofit2:converter-gson:2.9.0" + implementation "com.squareup.retrofit2:converter-scalars:2.9.0" + implementation 'com.google.code.gson:gson:2.8.6' + implementation "org.jsoup:jsoup:1.13.1" + implementation "pl.droidsonroids:jspoon:1.3.2" + implementation "pl.droidsonroids.retrofit2:converter-jspoon:1.3.2" + // Szkolny.eu libraries/forks implementation "eu.szkolny:agendacalendarview:1799f8ef47" implementation "eu.szkolny:cafebar:5bf0c618de" implementation "eu.szkolny:material-about-library:0534abf316" implementation "eu.szkolny:mhttp:af4b62e6e9" implementation "eu.szkolny:nachos:0e5dfcaceb" - //implementation project(":Navigation") - implementation "eu.szkolny:szkolny-font:1dab7d64ed" implementation "eu.szkolny.selective-dao:annotation:27f8f3f194" + implementation "pl.szczodrzynski:NavLib:v0.7.0" + implementation "pl.szczodrzynski:NumberSlidingPicker:2921225f76" + implementation "pl.szczodrzynski:RecyclerTabLayout:700f980584" + implementation "pl.szczodrzynski:Tachyon:551943a6b5" + implementation "pl.szczodrzynski.FSLogin:lib:2.0.0" kapt "eu.szkolny.selective-dao:codegen:27f8f3f194" + // Iconics & related + implementation "com.mikepenz:iconics-core:5.2.8" + implementation "com.mikepenz:iconics-views:5.2.8" + implementation "com.mikepenz:community-material-typeface:3.5.95.1-kotlin@aar" + implementation "eu.szkolny:szkolny-font:1dab7d64ed" + + // Other dependencies + implementation "cat.ereza:customactivityoncrash:2.3.0" + implementation "com.afollestad.material-dialogs:commons:0.9.6.0" + implementation "com.afollestad.material-dialogs:core:0.9.6.0" + implementation "com.applandeo:material-calendar-view:1.5.0" + implementation "com.daimajia.swipelayout:library:1.2.0@aar" + implementation "com.evernote:android-job:1.4.2" + implementation "com.github.antonKozyriatskyi:CircularProgressIndicator:1.2.2" + implementation "com.github.bassaer:chatmessageview:2.0.1" implementation "com.github.ChuckerTeam.Chucker:library:3.0.1" - //releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:3.0.1" + implementation "com.github.jetradarmobile:android-snowfall:1.2.0" + implementation "com.github.wulkanowy.uonet-request-signer:hebe-jvm:a99ca50a31" + implementation "com.heinrichreimersoftware:material-intro:1.5.8" // do not update + implementation "com.hypertrack:hyperlog:0.0.10" + implementation "com.jaredrummler:colorpicker:1.1.0" + implementation "com.qifan.powerpermission:powerpermission-coroutines:1.3.0" + implementation "com.qifan.powerpermission:powerpermission:1.3.0" + implementation "com.theartofdev.edmodo:android-image-cropper:2.8.0" // do not update + implementation "com.wdullaer:materialdatetimepicker:4.2.3" + implementation "com.yuyh.json:jsonviewer:1.0.6" + implementation "io.coil-kt:coil:1.1.1" + implementation "me.dm7.barcodescanner:zxing:1.9.8" + implementation "me.grantland:autofittextview:0.2.1" + implementation "me.leolin:ShortcutBadger:1.1.22@aar" + implementation "org.greenrobot:eventbus:3.2.0" + implementation "pl.droidsonroids.gif:android-gif-drawable:1.2.15" + implementation "uk.co.samuelwall:material-tap-target-prompt:2.14.0" + implementation("com.github.ozodrukh:CircularReveal:2.0.1@aar") {transitive = true} - //implementation 'com.github.wulkanowy:uonet-request-signer:master-SNAPSHOT' - //implementation 'com.github.kuba2k2.uonet-request-signer:android:master-63f094b14a-1' - - //implementation "org.redundent:kotlin-xml-builder:1.5.3" - - implementation 'com.github.wulkanowy.uonet-request-signer:hebe-jvm:a99ca50a31' - - implementation "androidx.work:work-runtime-ktx:${versions.work}" - - implementation 'com.hypertrack:hyperlog:0.0.10' - - implementation 'com.github.kuba2k2:RecyclerTabLayout:700f980584' - - implementation 'com.github.kuba2k2:Tachyon:551943a6b5' - - implementation "com.squareup.retrofit2:retrofit:${versions.retrofit}" - implementation "com.squareup.retrofit2:converter-gson:${versions.retrofit}" - - implementation 'com.github.jetradarmobile:android-snowfall:1.2.0' - - implementation "io.coil-kt:coil:0.9.2" - - implementation 'com.github.kuba2k2:NumberSlidingPicker:2921225f76' - - implementation 'com.google.android:flexbox:2.0.1' - - implementation 'com.qifan.powerpermission:powerpermission:1.3.0' - implementation 'com.qifan.powerpermission:powerpermission-coroutines:1.3.0' - - implementation 'com.github.kuba2k2.FSLogin:lib:2.0.0' - implementation 'pl.droidsonroids:jspoon:1.3.2' - implementation "com.squareup.retrofit2:converter-scalars:2.8.1" - implementation "pl.droidsonroids.retrofit2:converter-jspoon:1.3.2" -} -repositories { - mavenCentral() + // Debug-only dependencies + debugImplementation "com.amitshekhar.android:debug-db:1.0.5" } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/RegisterUnavailableDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/RegisterUnavailableDialog.kt index 6ecd494f..b9e733b8 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/RegisterUnavailableDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/RegisterUnavailableDialog.kt @@ -8,7 +8,7 @@ import android.text.method.LinkMovementMethod import android.view.LayoutInflater import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity -import coil.api.load +import coil.load import com.google.android.material.dialog.MaterialAlertDialogBuilder import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/day/DayDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/day/DayDialog.kt index c6a7b2f9..e5b7768d 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/day/DayDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/day/DayDialog.kt @@ -10,8 +10,6 @@ import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Observer import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.dialog.MaterialAlertDialogBuilder -import kotlinx.android.synthetic.main.row_lesson_change_item.view.* -import kotlinx.android.synthetic.main.row_teacher_absence_item.view.* import kotlinx.coroutines.* import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.db.entity.Lesson @@ -111,7 +109,7 @@ class DayDialog( } lessonChanges.ifNotEmpty { - b.lessonChangeContainer.visibility = View.VISIBLE + b.lessonChangeContainer.root.visibility = View.VISIBLE b.lessonChangeContainer.lessonChangeCount.text = it.size.toString() b.lessonChangeLayout.onClick { @@ -130,7 +128,7 @@ class DayDialog( } teacherAbsences.ifNotEmpty { - b.teacherAbsenceContainer.visibility = View.VISIBLE + b.teacherAbsenceContainer.root.visibility = View.VISIBLE b.teacherAbsenceContainer.teacherAbsenceCount.text = it.size.toString() b.teacherAbsenceLayout.onClick { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/event/EventManualDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/event/EventManualDialog.kt index 06b5f1a6..7240934b 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/event/EventManualDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/event/EventManualDialog.kt @@ -378,7 +378,7 @@ class EventManualDialog( customColor = color } }) - colorPickerDialog.show(activity.fragmentManager, "color-picker-dialog") + colorPickerDialog.show(activity.supportFragmentManager, "color-picker-dialog") } }} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/feedback/FeedbackFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/feedback/FeedbackFragment.kt index 63f7500f..3c33be8d 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/feedback/FeedbackFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/feedback/FeedbackFragment.kt @@ -14,8 +14,8 @@ import android.widget.PopupMenu import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment -import coil.Coil -import coil.api.load +import coil.imageLoader +import coil.request.ImageRequest import com.github.bassaer.chatmessageview.model.IChatUser import com.github.bassaer.chatmessageview.model.Message import com.github.bassaer.chatmessageview.view.ChatView @@ -34,14 +34,6 @@ import pl.szczodrzynski.edziennik.onClick import pl.szczodrzynski.edziennik.utils.Utils import pl.szczodrzynski.edziennik.utils.Utils.openUrl import java.util.* -import kotlin.collections.List -import kotlin.collections.any -import kotlin.collections.filter -import kotlin.collections.firstOrNull -import kotlin.collections.forEach -import kotlin.collections.forEachIndexed -import kotlin.collections.isNotEmpty -import kotlin.collections.mutableMapOf import kotlin.collections.set import kotlin.coroutines.CoroutineContext @@ -221,13 +213,15 @@ class FeedbackFragment : Fragment(), CoroutineScope { Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888).also { bmp -> launch { Log.d(TAG, "Created image for $userName") - Coil.load(activity, image) { - target { + val request = ImageRequest.Builder(activity) + .data(image) + .target { val canvas = Canvas(bmp) it.setBounds(0, 0, bmp.width, bmp.height) it.draw(canvas) } - } + .build() + activity.imageLoader.enqueue(request) } } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/cards/HomeAvailabilityCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/cards/HomeAvailabilityCard.kt index 957dff0c..fd54748e 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/cards/HomeAvailabilityCard.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/cards/HomeAvailabilityCard.kt @@ -12,7 +12,7 @@ import androidx.core.text.HtmlCompat import androidx.core.view.isVisible import androidx.core.view.plusAssign import androidx.core.view.setMargins -import coil.api.load +import coil.load import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginPrizeFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginPrizeFragment.kt index b9fdf43a..1c9634fc 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginPrizeFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginPrizeFragment.kt @@ -10,7 +10,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment -import coil.api.load +import coil.load import com.google.android.material.dialog.MaterialAlertDialogBuilder import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/viewholder/PlatformViewHolder.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/viewholder/PlatformViewHolder.kt index ea8a063d..2c08c27e 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/viewholder/PlatformViewHolder.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/viewholder/PlatformViewHolder.kt @@ -9,7 +9,7 @@ import android.view.ViewGroup import androidx.appcompat.app.AppCompatActivity import androidx.core.view.isVisible import androidx.recyclerview.widget.RecyclerView -import coil.api.load +import coil.load import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.databinding.LoginPlatformItemBinding import pl.szczodrzynski.edziennik.ui.modules.grades.viewholder.BindableViewHolder diff --git a/build.gradle b/build.gradle index fd64a16a..343e5fd5 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ buildscript { ext { - kotlin_version = '1.4.30' + kotlin_version = '1.4.31' release = [ versionName: "4.6.1", @@ -11,50 +11,9 @@ buildscript { setup = [ compileSdk: 30, - buildTools: "28.0.3", minSdk : 16, targetSdk : 30 ] - - versions = [ - gradleAndroid : '4.2.0-beta04', - - kotlin : ext.kotlin_version, - ktx : "1.3.2", - - androidX : '1.0.0', - annotation : '1.1.0', - recyclerView : '1.2.0-beta01', - material : '1.3.0', - appcompat : '1.3.0-beta01', - constraintLayout : '2.1.0-alpha2', - cardview : '1.0.0', - gridLayout : '1.0.0', - navigation : "2.0.0", - navigationFragment: "1.0.0", - legacy : "1.0.0", - - room : "2.2.6", - lifecycle : "2.3.0", - work : "2.5.0", - - firebase : '18.0.2', - firebasemessaging: "20.1.3", - play_services : "17.0.0", - - materialdialogs : "0.9.6.0", - materialdrawer : "817e45765c367034b03046aaea6e95eeabcb40e9", - iconics : "5.2.8", - font_cmd : "3.5.95.1-kotlin", - - navlib : "28cdab341470dffa5f331379fe9702482681d7de", - - gifdrawable : "1.2.15", - - retrofit : "2.6.4" - ] - versions.kotlin = '1.4.0' - versions.kotlin = '1.4.0' } repositories { @@ -62,11 +21,10 @@ buildscript { jcenter() } dependencies { - classpath "com.android.tools.build:gradle:${versions.gradleAndroid}" - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}" - classpath 'me.tatarka:gradle-retrolambda:3.7.0' + classpath "com.android.tools.build:gradle:4.2.0-beta06" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'com.google.gms:google-services:4.3.5' - classpath 'com.google.firebase:firebase-crashlytics-gradle:2.5.0' + classpath 'com.google.firebase:firebase-crashlytics-gradle:2.5.1' } } From cf4aa552e7681da912cccf0844b182ffc1dadc29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 21 Mar 2021 22:30:19 +0100 Subject: [PATCH 013/113] [Gradle] Update NavLib to fix multiple item selection issue. --- app/build.gradle | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 466d538a..8ad2fc81 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -115,15 +115,15 @@ dependencies { // Szkolny.eu libraries/forks implementation "eu.szkolny:agendacalendarview:1799f8ef47" implementation "eu.szkolny:cafebar:5bf0c618de" + implementation "eu.szkolny.fslogin:lib:2.0.0" implementation "eu.szkolny:material-about-library:0534abf316" implementation "eu.szkolny:mhttp:af4b62e6e9" implementation "eu.szkolny:nachos:0e5dfcaceb" implementation "eu.szkolny.selective-dao:annotation:27f8f3f194" - implementation "pl.szczodrzynski:NavLib:v0.7.0" - implementation "pl.szczodrzynski:NumberSlidingPicker:2921225f76" - implementation "pl.szczodrzynski:RecyclerTabLayout:700f980584" - implementation "pl.szczodrzynski:Tachyon:551943a6b5" - implementation "pl.szczodrzynski.FSLogin:lib:2.0.0" + implementation "pl.szczodrzynski:navlib:0.7.2" + implementation "pl.szczodrzynski:numberslidingpicker:2921225f76" + implementation "pl.szczodrzynski:recyclertablayout:700f980584" + implementation "pl.szczodrzynski:tachyon:551943a6b5" kapt "eu.szkolny.selective-dao:codegen:27f8f3f194" // Iconics & related From 85379b0bebbc2eeaf4386b33732d5a12584d13ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 21 Mar 2021 22:42:37 +0100 Subject: [PATCH 014/113] [Gradle] Remove unused dependencies. --- app/build.gradle | 4 ---- .../ui/modules/settings/SettingsLicenseActivity.kt | 12 ------------ app/src/main/res/xml/backup_descriptor.xml | 2 -- 3 files changed, 18 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 8ad2fc81..9f915809 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -84,7 +84,6 @@ dependencies { implementation "androidx.cardview:cardview:1.0.0" implementation "androidx.constraintlayout:constraintlayout:2.0.4" implementation "androidx.core:core-ktx:1.3.2" - implementation "androidx.gridlayout:gridlayout:1.0.0" implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.0" implementation "androidx.navigation:navigation-fragment-ktx:2.3.4" implementation "androidx.recyclerview:recyclerview:1.1.0" @@ -138,7 +137,6 @@ dependencies { implementation "com.afollestad.material-dialogs:core:0.9.6.0" implementation "com.applandeo:material-calendar-view:1.5.0" implementation "com.daimajia.swipelayout:library:1.2.0@aar" - implementation "com.evernote:android-job:1.4.2" implementation "com.github.antonKozyriatskyi:CircularProgressIndicator:1.2.2" implementation "com.github.bassaer:chatmessageview:2.0.1" implementation "com.github.ChuckerTeam.Chucker:library:3.0.1" @@ -158,8 +156,6 @@ dependencies { implementation "me.leolin:ShortcutBadger:1.1.22@aar" implementation "org.greenrobot:eventbus:3.2.0" implementation "pl.droidsonroids.gif:android-gif-drawable:1.2.15" - implementation "uk.co.samuelwall:material-tap-target-prompt:2.14.0" - implementation("com.github.ozodrukh:CircularReveal:2.0.1@aar") {transitive = true} // Debug-only dependencies debugImplementation "com.amitshekhar.android:debug-db:1.0.5" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsLicenseActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsLicenseActivity.kt index 192f1273..2e5aaf6f 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsLicenseActivity.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsLicenseActivity.kt @@ -79,12 +79,6 @@ class SettingsLicenseActivity : MaterialAboutActivity() { "Applandeo sp. z o.o.", OpenSourceLicense.APACHE_2, "https://github.com/Applandeo/Material-Calendar-View/"), - createLicenseCard(this, - "Android-Job", - "2007-2017", - "Evernote Corporation", - OpenSourceLicense.APACHE_2, - "https://github.com/evernote/android-job/"), createLicenseCard(this, "Custom Activity On Crash", "", @@ -151,12 +145,6 @@ class SettingsLicenseActivity : MaterialAboutActivity() { "Arthur Teplitzki, 2013 Edmodo, Inc.", OpenSourceLicense.APACHE_2, "https://github.com/ArthurHub/Android-Image-Cropper/"), - createLicenseCard(this, - "Material Tap Target Prompt", - "2016-2018", - "Samuel Wall", - OpenSourceLicense.APACHE_2, - "https://github.com/sjwall/MaterialTapTargetPrompt/"), createLicenseCard(this, "Android Swipe Layout", "2014", diff --git a/app/src/main/res/xml/backup_descriptor.xml b/app/src/main/res/xml/backup_descriptor.xml index 9b85b4b7..f5417ebb 100644 --- a/app/src/main/res/xml/backup_descriptor.xml +++ b/app/src/main/res/xml/backup_descriptor.xml @@ -2,6 +2,4 @@ - - From 177ffd92f7d7e685fbd8f7dfece17e029aa41a7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 21 Mar 2021 22:49:43 +0100 Subject: [PATCH 015/113] [Proguard] Remove unneeded rules. Move app proguard rules. --- app/build.gradle | 2 +- app/{proguard/app.pro => proguard-rules.pro} | 0 app/proguard/android-job.pro | 14 ------ app/proguard/blurry.pro | 1 - app/proguard/cafebar.pro | 25 ---------- app/proguard/iconics.pro | 14 ------ app/proguard/mhttp.pro | 48 -------------------- app/proguard/szkolny-font.pro | 1 - app/proguard/wear.pro | 21 --------- 9 files changed, 1 insertion(+), 125 deletions(-) rename app/{proguard/app.pro => proguard-rules.pro} (100%) delete mode 100644 app/proguard/android-job.pro delete mode 100644 app/proguard/blurry.pro delete mode 100644 app/proguard/cafebar.pro delete mode 100644 app/proguard/iconics.pro delete mode 100644 app/proguard/mhttp.pro delete mode 100644 app/proguard/szkolny-font.pro delete mode 100644 app/proguard/wear.pro diff --git a/app/build.gradle b/app/build.gradle index 9f915809..f146d6c8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -39,7 +39,7 @@ android { release { minifyEnabled = true shrinkResources = true - proguardFiles getDefaultProguardFile('proguard-android.txt') + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles fileTree('proguard').asList().toArray() } } diff --git a/app/proguard/app.pro b/app/proguard-rules.pro similarity index 100% rename from app/proguard/app.pro rename to app/proguard-rules.pro diff --git a/app/proguard/android-job.pro b/app/proguard/android-job.pro deleted file mode 100644 index 3f1a67be..00000000 --- a/app/proguard/android-job.pro +++ /dev/null @@ -1,14 +0,0 @@ --dontwarn com.evernote.android.job.gcm.** --dontwarn com.evernote.android.job.GcmAvailableHelper --dontwarn com.evernote.android.job.work.** --dontwarn com.evernote.android.job.WorkManagerAvailableHelper - --keep public class com.evernote.android.job.v21.PlatformJobService --keep public class com.evernote.android.job.v14.PlatformAlarmService --keep public class com.evernote.android.job.v14.PlatformAlarmReceiver --keep public class com.evernote.android.job.JobBootReceiver --keep public class com.evernote.android.job.JobRescheduleService --keep public class com.evernote.android.job.gcm.PlatformGcmService --keep public class com.evernote.android.job.work.PlatformWorker - --keep class com.evernote.android.job.** { *; } \ No newline at end of file diff --git a/app/proguard/blurry.pro b/app/proguard/blurry.pro deleted file mode 100644 index 980f404e..00000000 --- a/app/proguard/blurry.pro +++ /dev/null @@ -1 +0,0 @@ --keep class android.support.v8.renderscript.** { *; } \ No newline at end of file diff --git a/app/proguard/cafebar.pro b/app/proguard/cafebar.pro deleted file mode 100644 index 6f8147fd..00000000 --- a/app/proguard/cafebar.pro +++ /dev/null @@ -1,25 +0,0 @@ -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in D:\AndroidSDK/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the proguardFiles -# directive in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - --keep class !android.support.v7.internal.view.menu.**,android.support.** {*;} --keep class android.support.v7.graphics.** { *; } --dontwarn android.support.v7.graphics.** - --keep class android.support.design.widget.** { *; } --keep interface android.support.design.widget.** { *; } --dontwarn android.support.design.** diff --git a/app/proguard/iconics.pro b/app/proguard/iconics.pro deleted file mode 100644 index 0aa62122..00000000 --- a/app/proguard/iconics.pro +++ /dev/null @@ -1,14 +0,0 @@ -# Android iconics library - https://github.com/mikepenz/Android-Iconics -# Warning: works ONLY with iconics > 1.0.0 -# -# Tested on gradle config: -# -# compile 'com.mikepenz:iconics-core:1.7.1@aar' -# - --keep class com.mikepenz.iconics.** { *; } --keep class com.mikepenz.community_material_typeface_library.CommunityMaterial --keep class com.mikepenz.fontawesome_typeface_library.FontAwesome --keep class com.mikepenz.google_material_typeface_library.GoogleMaterial --keep class com.mikepenz.meteocons_typeface_library.Meteoconcs --keep class com.mikepenz.octicons_typeface_library.Octicons \ No newline at end of file diff --git a/app/proguard/mhttp.pro b/app/proguard/mhttp.pro deleted file mode 100644 index 6d3e4e38..00000000 --- a/app/proguard/mhttp.pro +++ /dev/null @@ -1,48 +0,0 @@ -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in /Users/wangchao/Work/android-sdk/sdk/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the proguardFiles -# directive in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} --dontwarn im.wangchao.** --dontwarn okio.** --dontwarn javax.annotation.Nullable --dontwarn javax.annotation.ParametersAreNonnullByDefault --keep class im.wangchao.** { *; } --keep class **_HttpBinder { *; } --keepclasseswithmembernames class * { - @im.wangchao.* ; -} --keepclasseswithmembernames class * { - @im.wangchao.* ; -} --keepclassmembers class * implements java.io.Serializable { - static final long serialVersionUID; - private static final java.io.ObjectStreamField[] serialPersistentFields; - !static !transient ; - private void writeObject(java.io.ObjectOutputStream); - private void readObject(java.io.ObjectInputStream); - java.lang.Object writeReplace(); - java.lang.Object readResolve(); -} -# okhttp --dontwarn okhttp3.** --dontwarn okio.** --dontwarn javax.annotation.** --dontwarn org.conscrypt.** -# A resource is loaded with a relative path so the package of this class must be preserved. --keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase - -# If you do not use Rx: --dontwarn rx.** \ No newline at end of file diff --git a/app/proguard/szkolny-font.pro b/app/proguard/szkolny-font.pro deleted file mode 100644 index 4e48be73..00000000 --- a/app/proguard/szkolny-font.pro +++ /dev/null @@ -1 +0,0 @@ --keep class com.mikepenz.szkolny_font_typeface_library.SzkolnyFont { *; } diff --git a/app/proguard/wear.pro b/app/proguard/wear.pro deleted file mode 100644 index f1b42451..00000000 --- a/app/proguard/wear.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile From da953c9b1c36e23cd6f3b5ee47ea8fe647765c8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 21 Mar 2021 23:39:51 +0100 Subject: [PATCH 016/113] [Gradle] Update CommunityMaterial to v5.8.55. --- app/build.gradle | 2 +- .../szczodrzynski/edziennik/MainActivity.kt | 14 ++++----- .../ui/modules/agenda/AgendaFragment.kt | 5 ++-- .../modules/attendance/AttendanceFragment.kt | 2 +- .../ui/modules/behaviour/NoticesAdapter.kt | 2 +- .../ui/modules/grades/GradesListFragment.kt | 5 ++-- .../modules/home/cards/HomeTimetableCard.kt | 4 +-- .../ui/modules/homework/HomeworkFragment.kt | 2 +- .../edziennik/ui/modules/login/LoginInfo.kt | 8 ++--- .../ui/modules/messages/MessageFragment.kt | 4 +-- .../ui/modules/messages/MessagesFragment.kt | 2 +- .../compose/MessagesComposeFragment.kt | 2 +- .../modules/settings/SettingsNewFragment.java | 30 +++++++++---------- .../ui/modules/timetable/TimetableFragment.kt | 3 +- .../ui/modules/views/AttachmentAdapter.kt | 4 +-- .../timetable/WidgetTimetableProvider.kt | 2 +- .../main/res/layout/dialog_event_details.xml | 25 +++++++++------- app/src/main/res/layout/event_list_item.xml | 5 ++-- .../res/layout/login_chooser_fragment.xml | 2 +- .../main/res/layout/login_form_fragment.xml | 2 +- .../layout/login_platform_list_fragment.xml | 2 +- .../res/layout/login_summary_fragment.xml | 2 +- app/src/main/res/layout/message_fragment.xml | 2 +- 23 files changed, 67 insertions(+), 64 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index f146d6c8..f9adae64 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -128,7 +128,7 @@ dependencies { // Iconics & related implementation "com.mikepenz:iconics-core:5.2.8" implementation "com.mikepenz:iconics-views:5.2.8" - implementation "com.mikepenz:community-material-typeface:3.5.95.1-kotlin@aar" + implementation "com.mikepenz:community-material-typeface:5.8.55.0-kotlin@aar" implementation "eu.szkolny:szkolny-font:1dab7d64ed" // Other dependencies diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt index 099763d2..de9b5f85 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt @@ -152,7 +152,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope { .withPopToHome(false) list += NavTarget(DRAWER_ITEM_TIMETABLE, R.string.menu_timetable, TimetableFragment::class) - .withIcon(CommunityMaterial.Icon2.cmd_timetable) + .withIcon(CommunityMaterial.Icon3.cmd_timetable) .withBadgeTypeId(TYPE_LESSON_CHANGE) .isInDrawer(true) @@ -162,7 +162,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope { .isInDrawer(true) list += NavTarget(DRAWER_ITEM_GRADES, R.string.menu_grades, GradesListFragment::class) - .withIcon(CommunityMaterial.Icon2.cmd_numeric_5_box_outline) + .withIcon(CommunityMaterial.Icon3.cmd_numeric_5_box_outline) .withBadgeTypeId(TYPE_GRADE) .isInDrawer(true) @@ -200,7 +200,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope { .isBelowSeparator(true) list += NavTarget(DRAWER_ITEM_SETTINGS, R.string.menu_settings, SettingsNewFragment::class) - .withIcon(CommunityMaterial.Icon2.cmd_settings_outline) + .withIcon(CommunityMaterial.Icon.cmd_cog_outline) .isInDrawer(true) .isStatic(true) .isBelowSeparator(true) @@ -208,7 +208,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope { // profile settings items list += NavTarget(DRAWER_PROFILE_ADD_NEW, R.string.menu_add_new_profile, null) - .withIcon(CommunityMaterial.Icon2.cmd_plus) + .withIcon(CommunityMaterial.Icon3.cmd_plus) .withDescription(R.string.drawer_add_new_profile_desc) .isInProfileList(true) @@ -237,7 +237,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope { if (App.devMode) { list += NavTarget(DRAWER_ITEM_DEBUG, R.string.menu_debug, DebugFragment::class) list += NavTarget(TARGET_LAB, R.string.menu_lab, LabFragment::class) - .withIcon(CommunityMaterial.Icon.cmd_flask_outline) + .withIcon(CommunityMaterial.Icon2.cmd_flask_outline) .isInDrawer(true) .isBelowSeparator(true) .isStatic(true) @@ -520,7 +520,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope { CafeBar.builder(this) .content(R.string.rate_snackbar_text) .icon(IconicsDrawable(this).apply { - icon = CommunityMaterial.Icon2.cmd_star_outline + icon = CommunityMaterial.Icon3.cmd_star_outline sizeDp = 20 colorInt = Themes.getPrimaryTextColor(this@MainActivity) }) @@ -565,7 +565,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope { BottomSheetSeparatorItem(false), BottomSheetPrimaryItem(false) .withTitle(R.string.menu_settings) - .withIcon(CommunityMaterial.Icon2.cmd_settings_outline) + .withIcon(CommunityMaterial.Icon.cmd_cog_outline) .withOnClickListener(View.OnClickListener { loadTarget(DRAWER_ITEM_SETTINGS) }), BottomSheetPrimaryItem(false) .withTitle(R.string.menu_feedback) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/agenda/AgendaFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/agenda/AgendaFragment.kt index 35750f43..367b00da 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/agenda/AgendaFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/agenda/AgendaFragment.kt @@ -18,7 +18,6 @@ import com.github.tibolte.agendacalendarview.models.CalendarEvent import com.github.tibolte.agendacalendarview.models.IDayItem import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial -import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial.Icon2 import com.mikepenz.iconics.utils.colorInt import com.mikepenz.iconics.utils.sizeDp import eu.szkolny.font.SzkolnyFont @@ -89,7 +88,7 @@ class AgendaFragment : Fragment(), CoroutineScope { }), BottomSheetPrimaryItem(true) .withTitle(R.string.menu_agenda_change_view) - .withIcon(if (type == Profile.AGENDA_DEFAULT) CommunityMaterial.Icon.cmd_calendar_outline else CommunityMaterial.Icon.cmd_format_list_bulleted_square) + .withIcon(if (type == Profile.AGENDA_DEFAULT) CommunityMaterial.Icon.cmd_calendar_outline else CommunityMaterial.Icon2.cmd_format_list_bulleted_square) .withOnClickListener(View.OnClickListener { activity.bottomSheet.close() type = if (type == Profile.AGENDA_DEFAULT) Profile.AGENDA_CALENDAR else Profile.AGENDA_DEFAULT @@ -111,7 +110,7 @@ class AgendaFragment : Fragment(), CoroutineScope { activity.navView.bottomBar.fabEnable = true activity.navView.bottomBar.fabExtendedText = getString(R.string.add) - activity.navView.bottomBar.fabIcon = Icon2.cmd_plus + activity.navView.bottomBar.fabIcon = CommunityMaterial.Icon3.cmd_plus activity.navView.setFabOnClickListener(View.OnClickListener { EventManualDialog(activity, app.profileId, defaultDate = actualDate) }) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/attendance/AttendanceFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/attendance/AttendanceFragment.kt index 0af177f9..194f36d2 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/attendance/AttendanceFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/attendance/AttendanceFragment.kt @@ -60,7 +60,7 @@ class AttendanceFragment : Fragment(), CoroutineScope { activity.bottomSheet.prependItems( BottomSheetPrimaryItem(true) .withTitle(R.string.menu_attendance_config) - .withIcon(CommunityMaterial.Icon2.cmd_settings_outline) + .withIcon(CommunityMaterial.Icon.cmd_cog_outline) .withOnClickListener(View.OnClickListener { activity.bottomSheet.close() AttendanceConfigDialog(activity, true, null, null) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/behaviour/NoticesAdapter.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/behaviour/NoticesAdapter.kt index 93f21191..a3288da2 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/behaviour/NoticesAdapter.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/behaviour/NoticesAdapter.kt @@ -50,7 +50,7 @@ class NoticesAdapter//getting the context and product list with constructor if (notice.type == Notice.TYPE_POSITIVE) { holder.noticesItemType.setImageDrawable( - IconicsDrawable(context, CommunityMaterial.Icon2.cmd_plus_circle_outline).apply { + IconicsDrawable(context, CommunityMaterial.Icon3.cmd_plus_circle_outline).apply { colorRes = R.color.md_green_600 sizeDp = 36 } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesListFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesListFragment.kt index 33d69c60..eb7fdcb1 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesListFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesListFragment.kt @@ -15,7 +15,6 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.Observer import androidx.recyclerview.widget.LinearLayoutManager import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial -import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial.Icon2 import kotlinx.coroutines.* import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.MainActivity.Companion.TARGET_GRADES_EDITOR @@ -71,7 +70,7 @@ class GradesListFragment : Fragment(), CoroutineScope { val adapter = GradesAdapter(activity) var firstRun = true - app.db.gradeDao().getAllOrderBy(App.profileId, app.gradesManager.getOrderByString()).observe(this@GradesListFragment, Observer { grades -> this@GradesListFragment.launch { + app.db.gradeDao().getAllOrderBy(App.profileId, app.gradesManager.getOrderByString()).observe(viewLifecycleOwner, Observer { grades -> this@GradesListFragment.launch { if (!isAdded) return@launch val items = when { @@ -135,7 +134,7 @@ class GradesListFragment : Fragment(), CoroutineScope { activity.bottomSheet.prependItems( BottomSheetPrimaryItem(true) .withTitle(R.string.menu_grades_config) - .withIcon(Icon2.cmd_settings_outline) + .withIcon(CommunityMaterial.Icon.cmd_cog_outline) .withOnClickListener(View.OnClickListener { activity.bottomSheet.close() GradesConfigDialog(activity, true, null, null) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/cards/HomeTimetableCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/cards/HomeTimetableCard.kt index a530eefc..a2e4f9d7 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/cards/HomeTimetableCard.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/cards/HomeTimetableCard.kt @@ -88,7 +88,7 @@ class HomeTimetableCard( holder.root += b.root b.settings.setImageDrawable( - IconicsDrawable(activity, CommunityMaterial.Icon2.cmd_settings_outline).apply { + IconicsDrawable(activity, CommunityMaterial.Icon.cmd_cog_outline).apply { colorAttr(activity, R.attr.colorIcon) sizeDp = 20 } @@ -102,7 +102,7 @@ class HomeTimetableCard( ) b.showCounter.setImageDrawable( - IconicsDrawable(activity, CommunityMaterial.Icon.cmd_fullscreen).apply { + IconicsDrawable(activity, CommunityMaterial.Icon2.cmd_fullscreen).apply { colorAttr(activity, R.attr.colorIcon) sizeDp = 20 } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/homework/HomeworkFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/homework/HomeworkFragment.kt index f757570a..c8a62def 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/homework/HomeworkFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/homework/HomeworkFragment.kt @@ -100,7 +100,7 @@ class HomeworkFragment : Fragment(), CoroutineScope { bottomBar.apply { fabEnable = true fabExtendedText = getString(R.string.add) - fabIcon = CommunityMaterial.Icon2.cmd_plus + fabIcon = CommunityMaterial.Icon3.cmd_plus } setFabOnClickListener(View.OnClickListener { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginInfo.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginInfo.kt index 949848a5..77036f19 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginInfo.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginInfo.kt @@ -110,7 +110,7 @@ object LoginInfo { FormField( keyName = "accountPin", name = R.string.login_hint_pin, - icon = CommunityMaterial.Icon2.cmd_lock, + icon = CommunityMaterial.Icon2.cmd_lock_outline, emptyText = R.string.login_error_no_pin, invalidText = R.string.login_error_incorrect_pin, errorCodes = mapOf(), @@ -157,7 +157,7 @@ object LoginInfo { FormField( keyName = "symbol", name = R.string.login_hint_symbol, - icon = CommunityMaterial.Icon2.cmd_school, + icon = CommunityMaterial.Icon3.cmd_school_outline, emptyText = R.string.login_error_no_symbol, invalidText = R.string.login_error_incorrect_symbol, errorCodes = mapOf( @@ -170,7 +170,7 @@ object LoginInfo { FormField( keyName = "devicePin", name = R.string.login_hint_pin, - icon = CommunityMaterial.Icon2.cmd_lock, + icon = CommunityMaterial.Icon2.cmd_lock_outline, emptyText = R.string.login_error_no_pin, invalidText = R.string.login_error_incorrect_pin, errorCodes = mapOf( @@ -252,7 +252,7 @@ object LoginInfo { FormField( keyName = "serverName", name = R.string.login_hint_address, - icon = CommunityMaterial.Icon2.cmd_web, + icon = CommunityMaterial.Icon3.cmd_web, emptyText = R.string.login_error_no_address, invalidText = R.string.login_error_incorrect_address, errorCodes = mapOf( diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessageFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessageFragment.kt index 19106004..2fcadf55 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessageFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessageFragment.kt @@ -65,7 +65,7 @@ class MessageFragment : Fragment(), CoroutineScope { if (!isAdded) return b.closeButton.setImageDrawable( - IconicsDrawable(activity, CommunityMaterial.Icon2.cmd_window_close).apply { + IconicsDrawable(activity, CommunityMaterial.Icon3.cmd_window_close).apply { colorAttr(activity, android.R.attr.textColorSecondary) sizeDp = 12 } @@ -231,7 +231,7 @@ class MessageFragment : Fragment(), CoroutineScope { bottomBar.apply { fabEnable = true fabExtendedText = getString(R.string.messages_reply) - fabIcon = CommunityMaterial.Icon2.cmd_reply + fabIcon = CommunityMaterial.Icon3.cmd_reply_outline } setFabOnClickListener(View.OnClickListener { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessagesFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessagesFragment.kt index 043cce7d..add36a3c 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessagesFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessagesFragment.kt @@ -97,7 +97,7 @@ class MessagesFragment : Fragment(), CoroutineScope { bottomBar.apply { fabEnable = true fabExtendedText = getString(R.string.compose) - fabIcon = CommunityMaterial.Icon2.cmd_pencil_outline + fabIcon = CommunityMaterial.Icon3.cmd_pencil_outline } setFabOnClickListener(View.OnClickListener { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/compose/MessagesComposeFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/compose/MessagesComposeFragment.kt index 96898871..942876f2 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/compose/MessagesComposeFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/compose/MessagesComposeFragment.kt @@ -316,7 +316,7 @@ class MessagesComposeFragment : Fragment(), CoroutineScope { activity.navView.bottomBar.apply { fabEnable = true fabExtendedText = getString(R.string.messages_compose_send) - fabIcon = CommunityMaterial.Icon2.cmd_send + fabIcon = CommunityMaterial.Icon3.cmd_send_outline setFabOnClickListener(View.OnClickListener { sendMessage() diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java index 3a6bffe4..d009cdf1 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java @@ -239,7 +239,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { new MaterialAboutActionItem( getString(R.string.settings_profile_notifications_text), getString(R.string.settings_profile_notifications_subtext), - icon(CommunityMaterial.Icon.cmd_filter_outline, iconSizeDp, iconColor) + icon(CommunityMaterial.Icon2.cmd_filter_outline, iconSizeDp, iconColor) ) .setOnClickAction(() -> { new NotificationFilterDialog(activity, null, null); @@ -295,7 +295,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { new MaterialAboutSwitchItem.Builder() .text(R.string.settings_theme_snowfall_text) .subText(R.string.settings_theme_snowfall_subtext) - .icon(icon(CommunityMaterial.Icon2.cmd_snowflake, iconSizeDp, iconColor)) + .icon(icon(CommunityMaterial.Icon3.cmd_snowflake, iconSizeDp, iconColor)) .setChecked(app.getConfig().getUi().getSnowfall()) .setOnCheckedChanged((item, isChecked) -> { app.getConfig().getUi().setSnowfall(isChecked); @@ -310,7 +310,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { new MaterialAboutActionItem( getString(R.string.settings_theme_theme_text), Themes.INSTANCE.getThemeName(activity), - icon(CommunityMaterial.Icon2.cmd_palette_outline, iconSizeDp, iconColor) + icon(CommunityMaterial.Icon3.cmd_palette_outline, iconSizeDp, iconColor) ) .setOnClickAction(() -> { new MaterialDialog.Builder(activity) @@ -354,7 +354,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { new MaterialAboutActionItem( getString(R.string.settings_theme_mini_drawer_buttons_text), null, - icon(CommunityMaterial.Icon.cmd_format_list_checks, iconSizeDp, iconColor) + icon(CommunityMaterial.Icon2.cmd_format_list_checks, iconSizeDp, iconColor) ) .setOnClickAction(() -> { List buttonIds = new ArrayList<>(); @@ -472,7 +472,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { items.add( new MaterialAboutSwitchItem.Builder( ) .text(R.string.settings_theme_open_drawer_on_back_pressed_text) - .icon(icon(CommunityMaterial.Icon2.cmd_menu_open, iconSizeDp, iconColor)) + .icon(icon(CommunityMaterial.Icon3.cmd_menu_open, iconSizeDp, iconColor)) .setChecked(app.getConfig().getUi().getOpenDrawerOnBackPressed()) .setOnCheckedChanged((item, isChecked) -> { app.getConfig().getUi().setOpenDrawerOnBackPressed(isChecked); @@ -521,7 +521,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { return new MaterialAboutSwitchItem.Builder() .text(R.string.settings_sync_wifi_text) .subText(R.string.settings_sync_wifi_subtext) - .icon(icon(CommunityMaterial.Icon2.cmd_wifi_strength_2, iconSizeDp, iconColor)) + .icon(icon(CommunityMaterial.Icon3.cmd_wifi_strength_2, iconSizeDp, iconColor)) .setChecked(app.getConfig().getSync().getOnlyWifi()) .setOnCheckedChanged((item, isChecked) -> { app.getConfig().getSync().setOnlyWifi(isChecked); @@ -721,7 +721,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { new MaterialAboutActionItem( getString(R.string.settings_sync_notifications_settings_text), getString(R.string.settings_sync_notifications_settings_subtext), - icon(CommunityMaterial.Icon2.cmd_settings_outline, iconSizeDp, iconColor) + icon(CommunityMaterial.Icon.cmd_cog_outline, iconSizeDp, iconColor) ) .setOnClickAction(() -> { String channel = app.getNotificationChannelsManager().getData().getKey(); @@ -794,7 +794,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { return new MaterialAboutSwitchItem.Builder() .text(R.string.settings_register_shared_events_text) .subText(R.string.settings_register_shared_events_subtext) - .icon(icon(CommunityMaterial.Icon2.cmd_share_outline, iconSizeDp, iconColor)) + .icon(icon(CommunityMaterial.Icon3.cmd_share_outline, iconSizeDp, iconColor)) .setChecked(app.getProfile().getEnableSharedEvents()) .setOnCheckedChanged((item, isChecked) -> { app.getProfile().setEnableSharedEvents(isChecked); @@ -822,7 +822,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { items.add(new MaterialAboutActionItem( getString(R.string.menu_grades_config), null, - icon(CommunityMaterial.Icon2.cmd_numeric_5_box_outline, iconSizeDp, iconColor) + icon(CommunityMaterial.Icon3.cmd_numeric_5_box_outline, iconSizeDp, iconColor) ).setOnClickAction(() -> new GradesConfigDialog(activity, false, null, null))); items.add(new MaterialAboutActionItem( @@ -958,7 +958,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { new MaterialAboutSwitchItem.Builder() .text(R.string.settings_register_count_in_seconds_text) .subText(R.string.settings_register_count_in_seconds_subtext) - .icon(icon(CommunityMaterial.Icon2.cmd_timer, iconSizeDp, iconColor)) + .icon(icon(CommunityMaterial.Icon3.cmd_timer, iconSizeDp, iconColor)) .setChecked(app.getConfig().getTimetable().getCountInSeconds()) .setOnCheckedChanged((item, isChecked) -> { app.getConfig().getTimetable().setCountInSeconds(isChecked); @@ -986,7 +986,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { items.add( new MaterialAboutSwitchItem.Builder() .text(R.string.settings_register_hide_sticks_from_old) - .icon(icon(CommunityMaterial.Icon2.cmd_numeric_1_box_outline, iconSizeDp, iconColor)) + .icon(icon(CommunityMaterial.Icon3.cmd_numeric_1_box_outline, iconSizeDp, iconColor)) .setChecked(app.getConfig().forProfile().getGrades().getHideSticksFromOld()) .setOnCheckedChanged((item, isChecked) -> { app.getConfig().forProfile().getGrades().setHideSticksFromOld(isChecked); @@ -1041,7 +1041,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { items.add(new MaterialAboutActionItem.Builder() .text(R.string.settings_about_privacy_policy_text) - .icon(icon(CommunityMaterial.Icon2.cmd_shield_outline, iconSizeDp, primaryTextOnPrimaryBg)) + .icon(icon(CommunityMaterial.Icon3.cmd_shield_outline, iconSizeDp, primaryTextOnPrimaryBg)) .setOnClickAction(ConvenienceBuilder.createWebsiteOnClickAction(activity, Uri.parse("https://szkolny.eu/privacy-policy"))) .build()); @@ -1055,7 +1055,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { items.add(new MaterialAboutActionItem.Builder() .text(R.string.settings_about_language_text) .subText(R.string.settings_about_language_subtext) - .icon(icon(CommunityMaterial.Icon2.cmd_translate, iconSizeDp, primaryTextOnPrimaryBg)) + .icon(icon(CommunityMaterial.Icon3.cmd_translate, iconSizeDp, primaryTextOnPrimaryBg)) .setOnClickAction(() -> { new MaterialDialog.Builder(activity) .title(getString(R.string.settings_about_language_dialog_title)) @@ -1090,7 +1090,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { items.add(new MaterialAboutActionItem.Builder() .text(R.string.settings_about_update_text) .subText(R.string.settings_about_update_subtext) - .icon(icon(CommunityMaterial.Icon2.cmd_update, iconSizeDp, primaryTextOnPrimaryBg)) + .icon(icon(CommunityMaterial.Icon3.cmd_update, iconSizeDp, primaryTextOnPrimaryBg)) .setOnClickAction(() -> { //open browser or intent here NetworkUtils net = new NetworkUtils(app); @@ -1110,7 +1110,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { items.add(new MaterialAboutActionItem.Builder() .text(R.string.settings_about_changelog_text) - .icon(icon(CommunityMaterial.Icon2.cmd_radar, iconSizeDp, primaryTextOnPrimaryBg)) + .icon(icon(CommunityMaterial.Icon3.cmd_radar, iconSizeDp, primaryTextOnPrimaryBg)) .setOnClickAction(() -> new ChangelogDialog(activity, null, null)) .build()); diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/timetable/TimetableFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/timetable/TimetableFragment.kt index 2e3695cc..d7b1b9a7 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/timetable/TimetableFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/timetable/TimetableFragment.kt @@ -17,7 +17,6 @@ import android.widget.Toast import androidx.fragment.app.Fragment import androidx.viewpager.widget.ViewPager import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial -import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial.Icon2 import com.wdullaer.materialdatetimepicker.date.DatePickerDialog import eu.szkolny.font.SzkolnyFont import kotlinx.coroutines.* @@ -192,7 +191,7 @@ class TimetableFragment : Fragment(), CoroutineScope { BottomSheetPrimaryItem(true) .withTitle(R.string.menu_generate_block_timetable) .withDescription(R.string.menu_generate_block_timetable_desc) - .withIcon(Icon2.cmd_table_large) + .withIcon(CommunityMaterial.Icon3.cmd_table_large) .withOnClickListener(View.OnClickListener { activity.bottomSheet.close() GenerateBlockTimetableDialog(activity) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/AttachmentAdapter.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/AttachmentAdapter.kt index 99abba4d..6f8bc4c7 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/AttachmentAdapter.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/AttachmentAdapter.kt @@ -69,7 +69,7 @@ class AttachmentAdapter( "jpg", "jpeg", "png", "bmp", "gif" -> SzkolnyFont.Icon.szf_file_image_outline "zip", "rar", "tar", "7z" -> SzkolnyFont.Icon.szf_zip_box_outline "html", "cpp", "c", "h", "css", "java", "py" -> SzkolnyFont.Icon.szf_file_code_outline - else -> CommunityMaterial.Icon.cmd_file_document_outline + else -> CommunityMaterial.Icon2.cmd_file_document_outline } b.chip.text = if (item.isDownloading) { @@ -83,7 +83,7 @@ class AttachmentAdapter( b.chip.chipIcon = IconicsDrawable(context).apply { icon = attachmentIcon - colorAttr(context, R.attr.colorSurface) + colorAttr(context, R.attr.colorOnSurface) sizeDp = 24 paddingDp = 2 } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/timetable/WidgetTimetableProvider.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/timetable/WidgetTimetableProvider.kt index 07db9ea2..daffae65 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/timetable/WidgetTimetableProvider.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/timetable/WidgetTimetableProvider.kt @@ -117,7 +117,7 @@ class WidgetTimetableProvider : AppWidgetProvider() { views.setImageViewBitmap( R.id.widgetTimetableRefresh, - IconicsDrawable(context, CommunityMaterial.Icon2.cmd_refresh).apply { + IconicsDrawable(context, CommunityMaterial.Icon3.cmd_refresh).apply { colorInt = Color.WHITE sizeDp = if (config.bigStyle) 24 else 16 }.toBitmap() diff --git a/app/src/main/res/layout/dialog_event_details.xml b/app/src/main/res/layout/dialog_event_details.xml index 11f57902..dc883137 100644 --- a/app/src/main/res/layout/dialog_event_details.xml +++ b/app/src/main/res/layout/dialog_event_details.xml @@ -206,6 +206,7 @@ app:flexWrap="wrap" app:justifyContent="flex_end"> + + + + + diff --git a/app/src/main/res/layout/event_list_item.xml b/app/src/main/res/layout/event_list_item.xml index 295ffdc2..f8f42ef9 100644 --- a/app/src/main/res/layout/event_list_item.xml +++ b/app/src/main/res/layout/event_list_item.xml @@ -73,14 +73,15 @@ android:textAppearance="@style/NavView.TextView.Medium" tools:text="Rozdział II: Panowanie Piastów i Jagiellonów.Przeniesiony z 11 grudnia. Nie wiem co się dzieje w tym roku nie będzie już religii w szkołach podstawowych w Polsce i Europie zachodniej Afryki" /> + diff --git a/app/src/main/res/layout/login_chooser_fragment.xml b/app/src/main/res/layout/login_chooser_fragment.xml index 27e6f309..6e83c68c 100644 --- a/app/src/main/res/layout/login_chooser_fragment.xml +++ b/app/src/main/res/layout/login_chooser_fragment.xml @@ -18,7 +18,7 @@ android:layout_marginHorizontal="24dp" android:layout_marginTop="32dp" app:iiv_color="@color/colorPrimary" - app:iiv_icon="cmd-school" + app:iiv_icon="cmd-school-outline" app:iiv_size="32dp" tools:srcCompat="@tools:sample/avatars" /> diff --git a/app/src/main/res/layout/login_form_fragment.xml b/app/src/main/res/layout/login_form_fragment.xml index 6bfb817f..ac4afd93 100644 --- a/app/src/main/res/layout/login_form_fragment.xml +++ b/app/src/main/res/layout/login_form_fragment.xml @@ -29,7 +29,7 @@ android:layout_height="32dp" android:layout_marginTop="32dp" app:iiv_color="@color/colorPrimary" - app:iiv_icon="cmd-account-circle" + app:iiv_icon="cmd-account-circle-outline" app:iiv_size="32dp" tools:srcCompat="@tools:sample/avatars" /> diff --git a/app/src/main/res/layout/login_platform_list_fragment.xml b/app/src/main/res/layout/login_platform_list_fragment.xml index 699177ff..7604f1c7 100644 --- a/app/src/main/res/layout/login_platform_list_fragment.xml +++ b/app/src/main/res/layout/login_platform_list_fragment.xml @@ -18,7 +18,7 @@ android:layout_marginHorizontal="24dp" android:layout_marginTop="32dp" app:iiv_color="@color/colorPrimary" - app:iiv_icon="cmd-tooltip-account" + app:iiv_icon="cmd-comment-account-outline" app:iiv_size="32dp" tools:srcCompat="@tools:sample/avatars" /> diff --git a/app/src/main/res/layout/login_summary_fragment.xml b/app/src/main/res/layout/login_summary_fragment.xml index 1b7aac65..174087e8 100644 --- a/app/src/main/res/layout/login_summary_fragment.xml +++ b/app/src/main/res/layout/login_summary_fragment.xml @@ -28,7 +28,7 @@ android:layout_marginHorizontal="24dp" android:layout_marginTop="32dp" app:iiv_color="@color/colorPrimary" - app:iiv_icon="cmd-account-check" + app:iiv_icon="cmd-account-check-outline" app:iiv_size="32dp" tools:srcCompat="@tools:sample/avatars" /> diff --git a/app/src/main/res/layout/message_fragment.xml b/app/src/main/res/layout/message_fragment.xml index a58f610f..bb252b11 100644 --- a/app/src/main/res/layout/message_fragment.xml +++ b/app/src/main/res/layout/message_fragment.xml @@ -217,7 +217,7 @@ android:layout_height="24dp" android:padding="4dp" app:iiv_color="?android:textColorSecondary" - app:iiv_icon="cmd-reply" + app:iiv_icon="cmd-reply-outline" tools:srcCompat="@android:drawable/ic_menu_revert" /> Date: Sun, 21 Mar 2021 23:47:14 +0100 Subject: [PATCH 017/113] [Gradle] Assign strict versions where required. --- app/build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index f9adae64..0e83e107 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,7 +99,7 @@ dependencies { implementation "com.google.android.gms:play-services-wearable:17.0.0" implementation "com.google.firebase:firebase-core:18.0.2" implementation "com.google.firebase:firebase-crashlytics:17.4.0" - implementation "com.google.firebase:firebase-messaging:20.1.3" + implementation("com.google.firebase:firebase-messaging") { version { strictly "20.1.3" } } // OkHttp, Retrofit, Gson, Jsoup implementation("com.squareup.okhttp3:okhttp") { version { strictly "3.12.13" } } @@ -142,12 +142,12 @@ dependencies { implementation "com.github.ChuckerTeam.Chucker:library:3.0.1" implementation "com.github.jetradarmobile:android-snowfall:1.2.0" implementation "com.github.wulkanowy.uonet-request-signer:hebe-jvm:a99ca50a31" - implementation "com.heinrichreimersoftware:material-intro:1.5.8" // do not update + implementation("com.heinrichreimersoftware:material-intro") { version { strictly "1.5.8" } } implementation "com.hypertrack:hyperlog:0.0.10" implementation "com.jaredrummler:colorpicker:1.1.0" implementation "com.qifan.powerpermission:powerpermission-coroutines:1.3.0" implementation "com.qifan.powerpermission:powerpermission:1.3.0" - implementation "com.theartofdev.edmodo:android-image-cropper:2.8.0" // do not update + implementation "com.theartofdev.edmodo:android-image-cropper:2.8.0" implementation "com.wdullaer:materialdatetimepicker:4.2.3" implementation "com.yuyh.json:jsonviewer:1.0.6" implementation "io.coil-kt:coil:1.1.1" @@ -155,7 +155,7 @@ dependencies { implementation "me.grantland:autofittextview:0.2.1" implementation "me.leolin:ShortcutBadger:1.1.22@aar" implementation "org.greenrobot:eventbus:3.2.0" - implementation "pl.droidsonroids.gif:android-gif-drawable:1.2.15" + implementation("pl.droidsonroids.gif:android-gif-drawable") { version { strictly "1.2.15" } } // Debug-only dependencies debugImplementation "com.amitshekhar.android:debug-db:1.0.5" From b4595446a3ce0a4e160ac67360ab444abb9d2dce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Mon, 22 Mar 2021 17:07:17 +0100 Subject: [PATCH 018/113] [Gradle] Change wrapper distribution from bin to all. --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1a62f29e..9bd0ad16 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Wed Feb 17 14:04:38 CET 2021 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME From 930ad12f5bb68aaa1bb878f410779c719e76cb7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Mon, 22 Mar 2021 19:03:51 +0100 Subject: [PATCH 019/113] [Git] Update .gitignore, remove ignored files. --- .gitignore | 195 ++++++++++++++++++++++++++++++++++-- .idea/.name | 1 - .idea/compiler.xml | 17 ---- .idea/dictionaries/Kuba.xml | 17 ++++ .idea/encodings.xml | 4 - .idea/jarRepositories.xml | 55 ---------- .idea/misc.xml | 59 ----------- 7 files changed, 203 insertions(+), 145 deletions(-) delete mode 100644 .idea/.name delete mode 100644 .idea/compiler.xml create mode 100644 .idea/dictionaries/Kuba.xml delete mode 100644 .idea/encodings.xml delete mode 100644 .idea/jarRepositories.xml delete mode 100644 .idea/misc.xml diff --git a/.gitignore b/.gitignore index 1864dd01..07e9f679 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,11 @@ + +# Created by https://www.toptal.com/developers/gitignore/api/android,androidstudio,gradle,java,kotlin +# Edit at https://www.toptal.com/developers/gitignore?templates=android,androidstudio,gradle,java,kotlin + +### Android ### # Built application files *.apk +*.aar *.ap_ *.aab @@ -23,7 +29,7 @@ build/ local.properties # Proguard folder generated by Eclipse -#proguard/ +# proguard/ # Log Files *.log @@ -40,22 +46,22 @@ captures/ .idea/tasks.xml .idea/gradle.xml .idea/assetWizardSettings.xml -.idea/dictionaries +#.idea/dictionaries .idea/libraries # Android Studio 3 in .gitignore file. .idea/caches .idea/modules.xml # Comment next line if keeping position of elements in Navigation Editor is relevant for you .idea/navEditor.xml -.idea/copyright/profiles_settings.xml # Keystore files # Uncomment the following lines if you do not want to check your keystore files in. -*.jks -*.keystore +#*.jks +#*.keystore # External native build folder generated in Android Studio 2.2 and later .externalNativeBuild +.cxx/ # Google Services (e.g. APIs or Firebase) # google-services.json @@ -82,9 +88,180 @@ lint/outputs/ lint/tmp/ # lint/reports/ -app/schemas/ +### Android Patch ### +gen-external-apklibs +output-metadata.json + +# Replacement of .externalNativeBuild directories introduced +# with Android Studio 3.5. + +### Java ### +# Compiled class file + +# Log file + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +!/*/libs/*.jar + +### Kotlin ### +# Compiled class file + +# Log file + +# BlueJ files + +# Mobile Tools for Java (J2ME) + +# Package Files # + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml + +### Gradle ### +.gradle + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Cache of project +.gradletasknamecache + +# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 +# gradle/wrapper/gradle-wrapper.properties + +### Gradle Patch ### +**/build/ + +### AndroidStudio ### +# Covers files to be ignored for android development using Android Studio. + +# Built application files + +# Files for the ART/Dalvik VM + +# Java class files + +# Generated files + +# Gradle files + +# Signing files +.signing/ + +# Local configuration file (sdk path, etc) + +# Proguard folder generated by Eclipse + +# Log Files + +# Android Studio +/*/build/ +/*/local.properties +/*/out +/*/*/build +/*/*/production +*.ipr +*~ +*.swp + +# Keystore files +*.jks +*.keystore + +# Google Services (e.g. APIs or Firebase) +# google-services.json + +# Android Patch + +# External native build folder generated in Android Studio 2.2 and later + +# NDK +obj/ + +# IntelliJ IDEA +*.iws +/out/ + +# User-specific configurations +.idea/caches/ +.idea/libraries/ +.idea/shelf/ +.idea/.name +.idea/compiler.xml +.idea/copyright/profiles_settings.xml +.idea/encodings.xml +.idea/misc.xml +.idea/scopes/scope_settings.xml +.idea/vcs.xml +.idea/jsLibraryMappings.xml +.idea/datasources.xml +.idea/dataSources.ids +.idea/sqlDataSources.xml +.idea/dynamic.xml +.idea/uiDesigner.xml +.idea/jarRepositories.xml + +# OS-specific files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Legacy Eclipse project files +.classpath +.project +.cproject +.settings/ + +# Mobile Tools for Java (J2ME) + +# Package Files # + +# virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml) + +## Plugin-specific files: + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Mongo Explorer plugin +.idea/mongoSettings.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +### AndroidStudio Patch ### + +!/gradle/wrapper/gradle-wrapper.jar + +# End of https://www.toptal.com/developers/gitignore/api/android,androidstudio,gradle,java,kotlin signatures/ - -app/.cxx -/i18n/ diff --git a/.idea/.name b/.idea/.name deleted file mode 100644 index 9ffcbb8a..00000000 --- a/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -Szkolny.eu \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index 8b487d4c..00000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/dictionaries/Kuba.xml b/.idea/dictionaries/Kuba.xml new file mode 100644 index 00000000..7910687c --- /dev/null +++ b/.idea/dictionaries/Kuba.xml @@ -0,0 +1,17 @@ + + + + autoryzacji + ciasteczko + csrf + edziennik + gson + hebe + idziennik + kuba + synergia + szczodrzyński + szkolny + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml deleted file mode 100644 index 15a15b21..00000000 --- a/.idea/encodings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml deleted file mode 100644 index 276cd1ca..00000000 --- a/.idea/jarRepositories.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 2f82ed79..00000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From 208d097986ab858970de08573ce3456f2960ff26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Mon, 22 Mar 2021 21:01:04 +0100 Subject: [PATCH 020/113] [UI] Add new Settings fragment. --- app/build.gradle | 4 +- .../pl/szczodrzynski/edziennik/Extensions.kt | 38 ++++ .../szczodrzynski/edziennik/MainActivity.kt | 9 +- .../ui/dialogs/bell/BellSyncConfigDialog.kt | 117 ++++++++++ .../ui/dialogs/event/EventManualDialog.kt | 32 +-- .../ui/dialogs/grade/GradeDetailsDialog.kt | 1 - .../{settings => grade}/GradesConfigDialog.kt | 2 +- .../ui/dialogs/settings/AppLanguageDialog.kt | 71 +++++++ .../dialogs/settings/MiniMenuConfigDialog.kt | 96 +++++++++ .../ui/dialogs/settings/ThemeChooserDialog.kt | 65 ++++++ .../ui/dialogs/sync/QuietHoursConfigDialog.kt | 107 ++++++++++ .../dialogs/sync/RegistrationConfigDialog.kt | 147 +++++++++++++ .../dialogs/sync/RegistrationEnableDialog.kt | 89 -------- .../ui/dialogs/sync/SyncIntervalDialog.kt | 77 +++++++ .../ui/modules/grades/GradesListFragment.kt | 2 +- .../grades/viewholder/StatsViewHolder.kt | 2 +- .../settings/MaterialAboutProfileItem.kt | 40 ++++ .../ui/modules/settings/SettingsCard.kt | 28 +++ .../ui/modules/settings/SettingsFragment.kt | 62 ++++++ .../modules/settings/SettingsNewFragment.java | 22 +- .../ui/modules/settings/SettingsUtil.kt | 188 ++++++++++++++++ .../settings/SettingsViewTypeManager.kt | 46 ++++ .../settings/cards/SettingsAboutCard.kt | 150 +++++++++++++ .../settings/cards/SettingsProfileCard.kt | 59 ++++++ .../settings/cards/SettingsRegisterCard.kt | 152 +++++++++++++ .../settings/cards/SettingsSyncCard.kt | 200 ++++++++++++++++++ .../settings/cards/SettingsThemeCard.kt | 96 +++++++++ .../szczodrzynski/edziennik/utils/Themes.kt | 41 ++-- app/src/main/res/layout/dialog_edit_text.xml | 32 +++ .../mal_material_about_profile_item.xml | 48 +++++ app/src/main/res/values-de/strings.xml | 22 +- app/src/main/res/values-en/strings.xml | 24 ++- app/src/main/res/values/strings.xml | 28 ++- 33 files changed, 1920 insertions(+), 177 deletions(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/bell/BellSyncConfigDialog.kt rename app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/{settings => grade}/GradesConfigDialog.kt (99%) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/AppLanguageDialog.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/MiniMenuConfigDialog.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/ThemeChooserDialog.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/QuietHoursConfigDialog.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/RegistrationConfigDialog.kt delete mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/RegistrationEnableDialog.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/SyncIntervalDialog.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/MaterialAboutProfileItem.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsCard.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsFragment.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsUtil.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsViewTypeManager.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsAboutCard.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsProfileCard.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsRegisterCard.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsSyncCard.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsThemeCard.kt create mode 100644 app/src/main/res/layout/dialog_edit_text.xml create mode 100644 app/src/main/res/layout/mal_material_about_profile_item.xml diff --git a/app/build.gradle b/app/build.gradle index 0e83e107..1766c3bf 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -115,7 +115,7 @@ dependencies { implementation "eu.szkolny:agendacalendarview:1799f8ef47" implementation "eu.szkolny:cafebar:5bf0c618de" implementation "eu.szkolny.fslogin:lib:2.0.0" - implementation "eu.szkolny:material-about-library:0534abf316" + implementation "eu.szkolny:material-about-library:fe4a5cd6f1" implementation "eu.szkolny:mhttp:af4b62e6e9" implementation "eu.szkolny:nachos:0e5dfcaceb" implementation "eu.szkolny.selective-dao:annotation:27f8f3f194" @@ -129,7 +129,7 @@ dependencies { implementation "com.mikepenz:iconics-core:5.2.8" implementation "com.mikepenz:iconics-views:5.2.8" implementation "com.mikepenz:community-material-typeface:5.8.55.0-kotlin@aar" - implementation "eu.szkolny:szkolny-font:1dab7d64ed" + implementation "eu.szkolny:szkolny-font:1.2" // Other dependencies implementation "cat.ereza:customactivityoncrash:2.3.0" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt index 71febada..aaf0eec7 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt @@ -1278,3 +1278,41 @@ operator fun Iterable>.get(key: K): V? { } fun ByteArray.toHexString() = joinToString("") { "%02x".format(it) } + +fun MutableList.after(what: E, insert: E) { + val index = indexOf(what) + if (index != -1) + add(index + 1, insert) +} + +fun MutableList.before(what: E, insert: E) { + val index = indexOf(what) + if (index != -1) + add(index, insert) +} + +fun MutableList.after(what: E, insert: Collection) { + val index = indexOf(what) + if (index != -1) + addAll(index + 1, insert) +} + +fun MutableList.before(what: E, insert: Collection) { + val index = indexOf(what) + if (index != -1) + addAll(index, insert) +} + +fun Context.getSyncInterval(interval: Int): String { + val hours = interval / 60 / 60 + val minutes = interval / 60 % 60 + val hoursText = if (hours > 0) + plural(R.plurals.time_till_hours, hours) + else + null + val minutesText = if (minutes > 0) + plural(R.plurals.time_till_minutes, minutes) + else + "" + return hoursText?.plus(" $minutesText") ?: minutesText +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt index de9b5f85..10caf080 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt @@ -79,6 +79,7 @@ import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesFragment import pl.szczodrzynski.edziennik.ui.modules.messages.compose.MessagesComposeFragment import pl.szczodrzynski.edziennik.ui.modules.notifications.NotificationsListFragment import pl.szczodrzynski.edziennik.ui.modules.settings.ProfileManagerFragment +import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsFragment import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsNewFragment import pl.szczodrzynski.edziennik.ui.modules.timetable.TimetableFragment import pl.szczodrzynski.edziennik.ui.modules.webpush.WebPushFragment @@ -199,12 +200,18 @@ class MainActivity : AppCompatActivity(), CoroutineScope { .isStatic(true) .isBelowSeparator(true) - list += NavTarget(DRAWER_ITEM_SETTINGS, R.string.menu_settings, SettingsNewFragment::class) + list += NavTarget(DRAWER_ITEM_SETTINGS, R.string.menu_settings, SettingsFragment::class) .withIcon(CommunityMaterial.Icon.cmd_cog_outline) .isInDrawer(true) .isStatic(true) .isBelowSeparator(true) + list += NavTarget(DRAWER_ITEM_SETTINGS+1, R.string.menu_settings, SettingsNewFragment::class) + .withIcon(CommunityMaterial.Icon3.cmd_seal) + .isInDrawer(true) + .isStatic(true) + .isBelowSeparator(true) + // profile settings items list += NavTarget(DRAWER_PROFILE_ADD_NEW, R.string.menu_add_new_profile, null) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/bell/BellSyncConfigDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/bell/BellSyncConfigDialog.kt new file mode 100644 index 00000000..13dcb6f9 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/bell/BellSyncConfigDialog.kt @@ -0,0 +1,117 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-20. + */ + +package pl.szczodrzynski.edziennik.ui.dialogs.bell + +import android.widget.TextView +import android.widget.Toast +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import androidx.core.widget.addTextChangedListener +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.google.android.material.textfield.TextInputEditText +import com.google.android.material.textfield.TextInputLayout +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import pl.szczodrzynski.edziennik.* +import pl.szczodrzynski.edziennik.utils.models.Time +import kotlin.coroutines.CoroutineContext + +class BellSyncConfigDialog( + val activity: AppCompatActivity, + val onChangeListener: (() -> Unit)? = null, + val onShowListener: ((tag: String) -> Unit)? = null, + val onDismissListener: ((tag: String) -> Unit)? = null +) : CoroutineScope { + companion object { + private const val TAG = "BellSyncConfigDialog" + } + + private lateinit var app: App + private lateinit var dialog: AlertDialog + + private val job = Job() + override val coroutineContext: CoroutineContext + get() = job + Dispatchers.Main + + // local variables go here + + private fun parse(input: String): Pair? { + if (input.length < 8) { + return null + } + if (input[2] != ':' || input[5] != ':') { + return null + } + val multiplier = when { + input[0] == '+' -> 1 + input[0] == '-' -> -1 + else -> return null + } + val time = Time.fromH_m_s("0" + input.substring(1)) + + return time to multiplier + } + + init { run { + if (activity.isFinishing) + return@run + onShowListener?.invoke(TAG) + app = activity.applicationContext as App + + dialog = MaterialAlertDialogBuilder(activity) + .setTitle(R.string.bell_sync_title) + .setView(R.layout.dialog_edit_text) + .setPositiveButton(R.string.ok, null) + .setNegativeButton(R.string.cancel, null) + .setNeutralButton(R.string.reset) { _, _ -> + app.config.timetable.bellSyncDiff = null + app.config.timetable.bellSyncMultiplier = 0 + onChangeListener?.invoke() + } + .setOnDismissListener { + onDismissListener?.invoke(TAG) + } + .show() + + val message = dialog.findViewById(android.R.id.title) + val editText = dialog.findViewById(android.R.id.text1) + val textLayout = dialog.findViewById(R.id.text_input_layout) + + message?.setText(R.string.bell_sync_adjust_content) + editText?.hint = "±H:MM:SS" + editText?.setText(app.config.timetable.bellSyncDiff?.let { + (if (app.config.timetable.bellSyncMultiplier == -1) "-" else "+") + it.stringHMS + } ?: "+0:00:00") + editText?.addTextChangedListener { text -> + val input = text?.toString() + textLayout?.error = + if (input != null && parse(input) == null) + activity.getString(R.string.bell_sync_adjust_error) + else + null + } + + dialog.getButton(AlertDialog.BUTTON_POSITIVE)?.onClick { + val input = editText?.text?.toString() ?: return@onClick + val parsed = parse(input) + if (parsed == null) { + Toast.makeText(activity, R.string.bell_sync_adjust_error, Toast.LENGTH_SHORT).show() + return@onClick + } + + val (time, multiplier) = parsed + app.config.timetable.bellSyncDiff = + if (time.value == 0) + null + else + time + app.config.timetable.bellSyncMultiplier = multiplier + + onChangeListener?.invoke() + dialog.dismiss() + } + }} +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/event/EventManualDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/event/EventManualDialog.kt index 7240934b..db5a2b09 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/event/EventManualDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/event/EventManualDialog.kt @@ -33,7 +33,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.data.db.full.EventFull import pl.szczodrzynski.edziennik.data.db.full.LessonFull import pl.szczodrzynski.edziennik.databinding.DialogEventManualV2Binding -import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegistrationEnableDialog +import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegistrationConfigDialog import pl.szczodrzynski.edziennik.ui.modules.views.TimeDropdown.Companion.DISPLAY_LESSONS import pl.szczodrzynski.edziennik.utils.Anim import pl.szczodrzynski.edziennik.utils.TextInputDropDown @@ -64,7 +64,7 @@ class EventManualDialog( private val app by lazy { activity.application as App } private lateinit var b: DialogEventManualV2Binding private lateinit var dialog: AlertDialog - private var profile: Profile? = null + private lateinit var profile: Profile private var customColor: Int? = null private val editingShared = editingEvent?.sharedBy != null @@ -80,9 +80,9 @@ class EventManualDialog( private var progressDialog: AlertDialog? = null - init { run { + init { launch { if (activity.isFinishing) - return@run + return@launch onShowListener?.invoke(TAG) EventBus.getDefault().register(this) b = DialogEventManualV2Binding.inflate(activity.layoutInflater) @@ -236,8 +236,15 @@ class EventManualDialog( progressDialog?.dismiss() } - private fun loadLists() { launch { - profile = withContext(Dispatchers.Default) { app.db.profileDao().getByIdNow(profileId) } + private fun loadLists() = launch { + val profile = withContext(Dispatchers.Default) { + app.db.profileDao().getByIdNow(profileId) + } + if (profile == null) { + Toast.makeText(activity, R.string.event_manual_no_profile, Toast.LENGTH_SHORT).show() + return@launch + } + this@EventManualDialog.profile = profile with (b.dateDropdown) { db = app.db @@ -380,7 +387,7 @@ class EventManualDialog( }) colorPickerDialog.show(activity.supportFragmentManager, "color-picker-dialog") } - }} + } private fun showRemoveEventDialog() { val shareNotice = when { @@ -417,12 +424,11 @@ class EventManualDialog( val share = b.shareSwitch.isChecked - if (share && profile?.registration != Profile.REGISTRATION_ENABLED) { - RegistrationEnableDialog(activity, profileId).showEventShareDialog { - if (it != null) - profile = it - saveEvent() - } + if (share && profile.registration != Profile.REGISTRATION_ENABLED) { + RegistrationConfigDialog(activity, profile, onChangeListener = { enabled -> + if (enabled) + saveEvent() + }).showEventShareDialog() return } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradeDetailsDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradeDetailsDialog.kt index 4877413f..5b9579ed 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradeDetailsDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradeDetailsDialog.kt @@ -13,7 +13,6 @@ import pl.szczodrzynski.edziennik.data.db.full.GradeFull import pl.szczodrzynski.edziennik.databinding.DialogGradeDetailsBinding import pl.szczodrzynski.edziennik.onClick import pl.szczodrzynski.edziennik.setTintColor -import pl.szczodrzynski.edziennik.ui.dialogs.settings.GradesConfigDialog import pl.szczodrzynski.edziennik.ui.modules.grades.GradesAdapter import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration import kotlin.coroutines.CoroutineContext diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/GradesConfigDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradesConfigDialog.kt similarity index 99% rename from app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/GradesConfigDialog.kt rename to app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradesConfigDialog.kt index e74f3577..20325447 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/GradesConfigDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradesConfigDialog.kt @@ -2,7 +2,7 @@ * Copyright (c) Kacper Ziubryniewicz 2020-1-16 */ -package pl.szczodrzynski.edziennik.ui.dialogs.settings +package pl.szczodrzynski.edziennik.ui.dialogs.grade import android.annotation.SuppressLint import androidx.appcompat.app.AlertDialog diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/AppLanguageDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/AppLanguageDialog.kt new file mode 100644 index 00000000..6db33e70 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/AppLanguageDialog.kt @@ -0,0 +1,71 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-19. + */ + +package pl.szczodrzynski.edziennik.ui.dialogs.settings + +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import pl.szczodrzynski.edziennik.* +import kotlin.coroutines.CoroutineContext + +class AppLanguageDialog( + val activity: AppCompatActivity, + val onShowListener: ((tag: String) -> Unit)? = null, + val onDismissListener: ((tag: String) -> Unit)? = null +) : CoroutineScope { + companion object { + private const val TAG = "AppLanguageDialog" + } + + private lateinit var app: App + private lateinit var dialog: AlertDialog + + private val job = Job() + override val coroutineContext: CoroutineContext + get() = job + Dispatchers.Main + + // local variables go here + + init { run { + if (activity.isFinishing) + return@run + onShowListener?.invoke(TAG) + app = activity.applicationContext as App + + val languages = mapOf( + null to R.string.language_system, + "pl" to R.string.language_polish, + "en" to R.string.language_english, + "de" to R.string.language_german + ) + val languageIds = languages.map { it.key } + val languageNames = languages.map { + activity.getString(it.value) + } + + dialog = MaterialAlertDialogBuilder(activity) + .setTitle(R.string.app_language_dialog_title) + //.setMessage(R.string.settings_about_language_dialog_text) + .setSingleChoiceItems( + languageNames.toTypedArray(), + languageIds.indexOf(app.config.ui.language), + null + ) + .setPositiveButton(R.string.ok) { _, _ -> + val which = dialog.listView.checkedItemPosition + + app.config.ui.language = languageIds[which] + activity.recreate() + } + .setNegativeButton(R.string.cancel, null) + .setOnDismissListener { + onDismissListener?.invoke(TAG) + } + .show() + }} +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/MiniMenuConfigDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/MiniMenuConfigDialog.kt new file mode 100644 index 00000000..61e95a8b --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/MiniMenuConfigDialog.kt @@ -0,0 +1,96 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-18. + */ + +package pl.szczodrzynski.edziennik.ui.dialogs.settings + +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.MainActivity +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ANNOUNCEMENTS +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ATTENDANCE +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_BEHAVIOUR +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_GRADES +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOME +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOMEWORK +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_NOTIFICATIONS +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_SETTINGS +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE +import pl.szczodrzynski.edziennik.R +import kotlin.coroutines.CoroutineContext + +class MiniMenuConfigDialog( + val activity: AppCompatActivity, + val onShowListener: ((tag: String) -> Unit)? = null, + val onDismissListener: ((tag: String) -> Unit)? = null +) : CoroutineScope { + companion object { + private const val TAG = "MiniMenuConfigDialog" + } + + private lateinit var app: App + private lateinit var dialog: AlertDialog + + private val job = Job() + override val coroutineContext: CoroutineContext + get() = job + Dispatchers.Main + + // local variables go here + + init { run { + if (activity.isFinishing) + return@run + onShowListener?.invoke(TAG) + app = activity.applicationContext as App + + val buttons = mapOf( + DRAWER_ITEM_HOME to R.string.menu_home_page, + DRAWER_ITEM_TIMETABLE to R.string.menu_timetable, + DRAWER_ITEM_AGENDA to R.string.menu_agenda, + DRAWER_ITEM_GRADES to R.string.menu_grades, + DRAWER_ITEM_MESSAGES to R.string.menu_messages, + DRAWER_ITEM_HOMEWORK to R.string.menu_homework, + DRAWER_ITEM_BEHAVIOUR to R.string.menu_notices, + DRAWER_ITEM_ATTENDANCE to R.string.menu_attendance, + DRAWER_ITEM_ANNOUNCEMENTS to R.string.menu_announcements, + DRAWER_ITEM_NOTIFICATIONS to R.string.menu_notifications, + DRAWER_ITEM_SETTINGS to R.string.menu_settings + ) + val miniMenuButtons = app.config.ui.miniMenuButtons + + dialog = MaterialAlertDialogBuilder(activity) + .setTitle(R.string.settings_theme_mini_drawer_buttons_dialog_title) + //.setMessage(R.string.settings_theme_mini_drawer_buttons_dialog_text) + .setMultiChoiceItems( + buttons.map { activity.getString(it.value) }.toTypedArray(), + buttons.map { it.key in miniMenuButtons }.toBooleanArray(), + null + ) + .setPositiveButton(R.string.ok) { _, _ -> + app.config.ui.miniMenuButtons = + buttons.keys.mapIndexedNotNull { index, id -> + if (dialog.listView.checkedItemPositions[index]) + id + else + null + } + + if (activity is MainActivity) { + activity.setDrawerItems() + activity.drawer.updateBadges() + } + } + .setNegativeButton(R.string.cancel, null) + .setOnDismissListener { + onDismissListener?.invoke(TAG) + } + .show() + }} +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/ThemeChooserDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/ThemeChooserDialog.kt new file mode 100644 index 00000000..ca9b2f11 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/ThemeChooserDialog.kt @@ -0,0 +1,65 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-18. + */ + +package pl.szczodrzynski.edziennik.ui.dialogs.settings + +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.utils.Themes +import kotlin.coroutines.CoroutineContext + +class ThemeChooserDialog( + val activity: AppCompatActivity, + val onShowListener: ((tag: String) -> Unit)? = null, + val onDismissListener: ((tag: String) -> Unit)? = null +) : CoroutineScope { + companion object { + private const val TAG = "ThemeChooserDialog" + } + + private lateinit var app: App + private lateinit var dialog: AlertDialog + + private val job = Job() + override val coroutineContext: CoroutineContext + get() = job + Dispatchers.Main + + // local variables go here + + init { run { + if (activity.isFinishing) + return@run + onShowListener?.invoke(TAG) + app = activity.applicationContext as App + + dialog = MaterialAlertDialogBuilder(activity) + .setTitle(R.string.settings_theme_theme_text) + .setSingleChoiceItems( + Themes.getThemeNames(activity).toTypedArray(), + Themes.themeIndex, + null + ) + .setPositiveButton(R.string.ok) { _, _ -> + val which = dialog.listView.checkedItemPosition + + val theme = Themes.themeList[which] + if (app.config.ui.theme == theme.id) + return@setPositiveButton + app.config.ui.theme = theme.id + Themes.themeIndex = which + activity.recreate() + } + .setNegativeButton(R.string.cancel, null) + .setOnDismissListener { + onDismissListener?.invoke(TAG) + } + .show() + }} +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/QuietHoursConfigDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/QuietHoursConfigDialog.kt new file mode 100644 index 00000000..5c933e20 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/QuietHoursConfigDialog.kt @@ -0,0 +1,107 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-20. + */ + +package pl.szczodrzynski.edziennik.ui.dialogs.sync + +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.google.android.material.timepicker.MaterialTimePicker +import com.google.android.material.timepicker.TimeFormat +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.utils.models.Time +import kotlin.coroutines.CoroutineContext + +class QuietHoursConfigDialog( + val activity: AppCompatActivity, + val onChangeListener: (() -> Unit)? = null, + val onShowListener: ((tag: String) -> Unit)? = null, + val onDismissListener: ((tag: String) -> Unit)? = null +) : CoroutineScope { + companion object { + private const val TAG = "QuietHoursConfigDialog" + } + + private lateinit var app: App + private lateinit var dialog: AlertDialog + + private val job = Job() + override val coroutineContext: CoroutineContext + get() = job + Dispatchers.Main + + // local variables go here + + init { run { + if (activity.isFinishing) + return@run + onShowListener?.invoke(TAG) + app = activity.applicationContext as App + + dialog = MaterialAlertDialogBuilder(activity) + .setTitle(R.string.settings_sync_quiet_hours_dialog_title) + .setItems(arrayOf( + activity.getString(R.string.settings_sync_quiet_hours_set_beginning), + activity.getString(R.string.settings_sync_quiet_hours_set_end) + )) { dialog, which -> + when (which) { + 0 -> configStartTime() + 1 -> configEndTime() + } + dialog.dismiss() + } + .setNegativeButton(R.string.cancel, null) + .setOnDismissListener { + onDismissListener?.invoke(TAG) + } + .show() + }} + + private fun configStartTime() { + onShowListener?.invoke(TAG + "Start") + + val time = app.config.sync.quietHoursStart ?: return + val picker = MaterialTimePicker.Builder() + .setTitleText(R.string.settings_sync_quiet_hours_set_beginning) + .setTimeFormat(TimeFormat.CLOCK_24H) + .setHour(time.hour) + .setMinute(time.minute) + .build() + + picker.show(activity.supportFragmentManager, TAG) + picker.addOnPositiveButtonClickListener { + app.config.sync.quietHoursEnabled = true + app.config.sync.quietHoursStart = Time(picker.hour, picker.minute, 0) + onChangeListener?.invoke() + } + picker.addOnDismissListener { + onDismissListener?.invoke(TAG + "Start") + } + } + + private fun configEndTime() { + onShowListener?.invoke(TAG + "End") + + val time = app.config.sync.quietHoursEnd ?: return + val picker = MaterialTimePicker.Builder() + .setTitleText(R.string.settings_sync_quiet_hours_set_end) + .setTimeFormat(TimeFormat.CLOCK_24H) + .setHour(time.hour) + .setMinute(time.minute) + .build() + + picker.show(activity.supportFragmentManager, TAG) + picker.addOnPositiveButtonClickListener { + app.config.sync.quietHoursEnabled = true + app.config.sync.quietHoursEnd = Time(picker.hour, picker.minute, 0) + onChangeListener?.invoke() + } + picker.addOnDismissListener { + onDismissListener?.invoke(TAG + "End") + } + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/RegistrationConfigDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/RegistrationConfigDialog.kt new file mode 100644 index 00000000..9470534d --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/RegistrationConfigDialog.kt @@ -0,0 +1,147 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2020-3-15. + */ + +package pl.szczodrzynski.edziennik.ui.dialogs.sync + +import android.text.Html +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import kotlinx.coroutines.* +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi +import pl.szczodrzynski.edziennik.data.api.task.AppSync +import pl.szczodrzynski.edziennik.data.db.entity.Profile +import kotlin.coroutines.CoroutineContext + +class RegistrationConfigDialog( + val activity: AppCompatActivity, + val profile: Profile, + val onChangeListener: ((enabled: Boolean) -> Unit)? = null, + val onShowListener: ((tag: String) -> Unit)? = null, + val onDismissListener: ((tag: String) -> Unit)? = null +) : CoroutineScope { + companion object { + private const val TAG = "RegistrationEnableDialog" + } + + private lateinit var app: App + private lateinit var dialog: AlertDialog + + private val job = Job() + override val coroutineContext: CoroutineContext + get() = job + Dispatchers.Main + + // local variables go here + + init { run { + if (activity.isFinishing) + return@run + app = activity.applicationContext as App + }} + + fun showEventShareDialog() { + onShowListener?.invoke(TAG + "EventShare") + dialog = MaterialAlertDialogBuilder(activity) + .setTitle(R.string.registration_config_event_sharing_title) + .setMessage(R.string.registration_config_event_sharing_text) + .setPositiveButton(R.string.i_agree) { _, _ -> + enableRegistration() + } + .setNegativeButton(R.string.cancel, null) + .setOnDismissListener { + onDismissListener?.invoke(TAG + "EventShare") + } + .show() + } + + fun showEnableDialog() { + onShowListener?.invoke(TAG + "Enable") + dialog = MaterialAlertDialogBuilder(activity) + .setTitle(R.string.registration_config_title) + .setMessage(Html.fromHtml(app.getString(R.string.registration_config_enable_text))) + .setPositiveButton(R.string.i_agree) { _, _ -> + enableRegistration() + } + .setNegativeButton(R.string.i_disagree, null) + .setOnDismissListener { + onDismissListener?.invoke(TAG + "Enable") + } + .show() + } + + fun showDisableDialog() { + onShowListener?.invoke(TAG + "Disable") + dialog = MaterialAlertDialogBuilder(activity) + .setTitle(R.string.registration_config_title) + .setMessage(Html.fromHtml(app.getString(R.string.registration_config_disable_text))) + .setPositiveButton(R.string.ok) { _, _ -> + disableRegistration() + } + .setNegativeButton(R.string.cancel, null) + .setOnDismissListener { + onDismissListener?.invoke(TAG + "Disable") + } + .show() + } + + private fun enableRegistration() = launch { + onShowListener?.invoke(TAG + "Enabling") + dialog = MaterialAlertDialogBuilder(activity) + .setTitle(R.string.please_wait) + .setMessage(R.string.registration_config_enable_progress_text) + .setCancelable(false) + .setOnDismissListener { + onDismissListener?.invoke(TAG + "Enabling") + } + .show() + + withContext(Dispatchers.Default) { + profile.registration = Profile.REGISTRATION_ENABLED + + // force full registration of the user + App.config.getFor(profile.id).hash = "" + + AppSync(app, mutableListOf(), listOf(profile), SzkolnyApi(app)).run( + 0L, + markAsSeen = true + ) + app.db.profileDao().add(profile) + if (profile.id == App.profileId) { + App.profile.registration = profile.registration + } + } + + dialog.dismiss() + onChangeListener?.invoke(true) + } + + private fun disableRegistration() = launch { + onShowListener?.invoke(TAG + "Disabling") + dialog = MaterialAlertDialogBuilder(activity) + .setTitle(R.string.please_wait) + .setMessage(R.string.registration_config_disable_progress_text) + .setCancelable(false) + .setOnDismissListener { + onDismissListener?.invoke(TAG + "Disabling") + } + .show() + + withContext(Dispatchers.Default) { + profile.registration = Profile.REGISTRATION_DISABLED + + SzkolnyApi(app).runCatching(activity) { + unregisterAppUser(profile.userCode) + } + app.db.profileDao().add(profile) + if (profile.id == App.profileId) { + App.profile.registration = profile.registration + } + } + + dialog.dismiss() + onChangeListener?.invoke(false) + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/RegistrationEnableDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/RegistrationEnableDialog.kt deleted file mode 100644 index 7fc0caf3..00000000 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/RegistrationEnableDialog.kt +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) Kuba Szczodrzyński 2020-3-15. - */ - -package pl.szczodrzynski.edziennik.ui.dialogs.sync - -import android.text.Html -import androidx.appcompat.app.AlertDialog -import androidx.appcompat.app.AppCompatActivity -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import kotlinx.coroutines.* -import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.R -import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi -import pl.szczodrzynski.edziennik.data.api.task.AppSync -import pl.szczodrzynski.edziennik.data.db.entity.Profile -import kotlin.coroutines.CoroutineContext - -class RegistrationEnableDialog( - val activity: AppCompatActivity, - val profileId: Int -) : CoroutineScope { - companion object { - private const val TAG = "RegistrationEnableDialog" - } - - private lateinit var app: App - - private val job = Job() - override val coroutineContext: CoroutineContext - get() = job + Dispatchers.Main - - // local variables go here - private var progressDialog: AlertDialog? = null - - init { run { - if (activity.isFinishing) - return@run - app = activity.applicationContext as App - }} - - fun showEventShareDialog(onSuccess: (profile: Profile?) -> Unit) { - MaterialAlertDialogBuilder(activity) - .setTitle(R.string.event_manual_need_registration_title) - .setMessage(R.string.event_manual_need_registration_text) - .setPositiveButton(R.string.ok) { dialog, which -> - enableRegistration(onSuccess) - } - .setNegativeButton(R.string.cancel, null) - .show() - } - - fun showEnableDialog(onSuccess: (profile: Profile?) -> Unit) { - MaterialAlertDialogBuilder(activity) - .setTitle(R.string.registration_enable_dialog_title) - .setMessage(Html.fromHtml(app.getString(R.string.registration_enable_dialog_text))) - .setPositiveButton(R.string.ok) { dialog, which -> - enableRegistration(onSuccess) - } - .setNegativeButton(R.string.cancel, null) - .show() - } - - private fun enableRegistration(onSuccess: (profile: Profile?) -> Unit) { launch { - progressDialog = MaterialAlertDialogBuilder(activity) - .setTitle(R.string.please_wait) - .setMessage(R.string.registration_enable_progress_text) - .setCancelable(false) - .show() - - val profile = withContext(Dispatchers.Default) { - val profile = app.db.profileDao().getByIdNow(profileId) ?: return@withContext null - profile.registration = Profile.REGISTRATION_ENABLED - - // force full registration of the user - App.config.getFor(profile.id).hash = "" - - AppSync(app, mutableListOf(), listOf(profile), SzkolnyApi(app)).run(0L, markAsSeen = true) - app.db.profileDao().add(profile) - if (profile.id == App.profileId) { - App.profile.registration = profile.registration - } - return@withContext profile - } - - progressDialog?.dismiss() - onSuccess(profile) - }} -} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/SyncIntervalDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/SyncIntervalDialog.kt new file mode 100644 index 00000000..6f4f027b --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/SyncIntervalDialog.kt @@ -0,0 +1,77 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-20. + */ + +package pl.szczodrzynski.edziennik.ui.dialogs.sync + +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import pl.szczodrzynski.edziennik.* +import kotlin.coroutines.CoroutineContext + +class SyncIntervalDialog( + val activity: AppCompatActivity, + val onChangeListener: (() -> Unit)? = null, + val onShowListener: ((tag: String) -> Unit)? = null, + val onDismissListener: ((tag: String) -> Unit)? = null +) : CoroutineScope { + companion object { + private const val TAG = "SyncIntervalDialog" + } + + private lateinit var app: App + private lateinit var dialog: AlertDialog + + private val job = Job() + override val coroutineContext: CoroutineContext + get() = job + Dispatchers.Main + + // local variables go here + + init { run { + if (activity.isFinishing) + return@run + onShowListener?.invoke(TAG) + app = activity.applicationContext as App + + val intervals = listOf( + 30 * MINUTE, + 45 * MINUTE, + 60 * MINUTE, + 90 * MINUTE, + 2 * HOUR, + 3 * HOUR, + 4 * HOUR, + 6 * HOUR, + 10 * HOUR + ) + val intervalNames = intervals.map { + activity.getSyncInterval(it.toInt()) + } + + dialog = MaterialAlertDialogBuilder(activity) + .setTitle(R.string.settings_sync_sync_interval_dialog_title) + //.setMessage(R.string.settings_sync_sync_interval_dialog_text) + .setSingleChoiceItems( + intervalNames.toTypedArray(), + intervals.indexOf(app.config.sync.interval.toLong()), + null + ) + .setPositiveButton(R.string.ok) { _, _ -> + val which = dialog.listView.checkedItemPosition + + val interval = intervals[which] + app.config.sync.interval = interval.toInt() + onChangeListener?.invoke() + } + .setNegativeButton(R.string.cancel, null) + .setOnDismissListener { + onDismissListener?.invoke(TAG) + } + .show() + }} +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesListFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesListFragment.kt index eb7fdcb1..63521e97 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesListFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesListFragment.kt @@ -23,7 +23,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_GRADE import pl.szczodrzynski.edziennik.data.db.full.GradeFull import pl.szczodrzynski.edziennik.databinding.GradesListFragmentBinding import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradeDetailsDialog -import pl.szczodrzynski.edziennik.ui.dialogs.settings.GradesConfigDialog +import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradesConfigDialog import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesAverages import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesSemester import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesStats diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/StatsViewHolder.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/StatsViewHolder.kt index de1b071f..532ade84 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/StatsViewHolder.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/StatsViewHolder.kt @@ -15,7 +15,7 @@ import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.databinding.GradesItemStatsBinding import pl.szczodrzynski.edziennik.onClick -import pl.szczodrzynski.edziennik.ui.dialogs.settings.GradesConfigDialog +import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradesConfigDialog import pl.szczodrzynski.edziennik.ui.modules.grades.GradesAdapter import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesStats import java.text.DecimalFormat diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/MaterialAboutProfileItem.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/MaterialAboutProfileItem.kt new file mode 100644 index 00000000..dfff3246 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/MaterialAboutProfileItem.kt @@ -0,0 +1,40 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-17. + */ + +package pl.szczodrzynski.edziennik.ui.modules.settings + +import android.content.Context +import android.view.View +import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder +import com.danielstone.materialaboutlibrary.items.MaterialAboutTitleItem + +class MaterialAboutProfileItem(item: MaterialAboutTitleItem) : MaterialAboutTitleItem(item) { + companion object { + fun getViewHolder(view: View): MaterialAboutItemViewHolder = + MaterialAboutTitleItem.getViewHolder(view) + + fun setupItem( + holder: MaterialAboutTitleItemViewHolder, + item: MaterialAboutProfileItem, + context: Context + ) = MaterialAboutTitleItem.setupItem(holder, item, context) + } + + override fun getType(): Int { + return SettingsViewTypeManager.ItemType.PROFILE_ITEM + } + + override fun getDetailString() = "MaterialAboutProfileItem{" + + "text=" + text + + ", textRes=" + textRes + + ", desc=" + desc + + ", descRes=" + descRes + + ", icon=" + icon + + ", iconRes=" + iconRes + + ", onClickAction=" + onClickAction + + ", onLongClickAction=" + onLongClickAction + + '}' + + override fun clone() = MaterialAboutProfileItem(this) +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsCard.kt new file mode 100644 index 00000000..c31116d9 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsCard.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-17. + */ + +package pl.szczodrzynski.edziennik.ui.modules.settings + +import com.danielstone.materialaboutlibrary.items.MaterialAboutItem +import com.danielstone.materialaboutlibrary.model.MaterialAboutCard +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.MainActivity + +abstract class SettingsCard( + protected val util: SettingsUtil, +) { + protected val app: App = util.activity.application as App + protected val activity: MainActivity = util.activity + + protected val configGlobal by lazy { app.config } + protected val configProfile by lazy { app.config.forProfile() } + + val card by lazy { + buildCard() + } + + protected abstract fun buildCard(): MaterialAboutCard + protected abstract fun getItems(): List + protected abstract fun getItemsMore(): List +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsFragment.kt new file mode 100644 index 00000000..cf7fa625 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsFragment.kt @@ -0,0 +1,62 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-16. + */ + +package pl.szczodrzynski.edziennik.ui.modules.settings + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.danielstone.materialaboutlibrary.MaterialAboutFragment +import com.danielstone.materialaboutlibrary.model.MaterialAboutList +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.MainActivity +import pl.szczodrzynski.edziennik.ui.modules.settings.cards.* +import kotlin.coroutines.CoroutineContext + +class SettingsFragment : MaterialAboutFragment(), CoroutineScope { + companion object { + private const val TAG = "SettingsFragment" + } + + private lateinit var app: App + private lateinit var activity: MainActivity + + private val job: Job = Job() + override val coroutineContext: CoroutineContext + get() = job + Dispatchers.Main + + private val util by lazy { + SettingsUtil(activity) { + refreshMaterialAboutList() + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + activity = (getActivity() as MainActivity?) ?: return null + app = activity.application as App + return super.onCreateView(inflater, container, savedInstanceState) + } + + override fun getViewTypeManager() = + SettingsViewTypeManager() + + override fun getMaterialAboutList(activityContext: Context?): MaterialAboutList { + return MaterialAboutList( + SettingsProfileCard(util).card, + SettingsThemeCard(util).card, + SettingsSyncCard(util).card, + SettingsRegisterCard(util).card, + SettingsAboutCard(util).card, + ) + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java index d009cdf1..80aee4dd 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java @@ -53,8 +53,8 @@ import pl.szczodrzynski.edziennik.network.NetworkUtils; import pl.szczodrzynski.edziennik.sync.SyncWorker; import pl.szczodrzynski.edziennik.sync.UpdateWorker; import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog; +import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradesConfigDialog; import pl.szczodrzynski.edziennik.ui.dialogs.settings.AttendanceConfigDialog; -import pl.szczodrzynski.edziennik.ui.dialogs.settings.GradesConfigDialog; import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog; import pl.szczodrzynski.edziennik.ui.dialogs.sync.NotificationFilterDialog; import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity; @@ -641,6 +641,9 @@ public class SettingsNewFragment extends MaterialAboutFragment { Time time = app.getConfig().getSync().getQuietHoursStart(); if (time == null) time = new Time(22, 30, 0); + Time timeEnd = app.getConfig().getSync().getQuietHoursEnd(); + if (timeEnd == null) + app.getConfig().getSync().setQuietHoursEnd(new Time(5, 30, 0)); TimePickerDialog.newInstance((v2, hourOfDay, minute, second) -> { app.getConfig().getSync().setQuietHoursEnabled(true); app.getConfig().getSync().setQuietHoursStart(new Time(hourOfDay, minute, second)); @@ -654,6 +657,9 @@ public class SettingsNewFragment extends MaterialAboutFragment { Time time = app.getConfig().getSync().getQuietHoursEnd(); if (time == null) time = new Time(5, 30, 0); + Time timeStart = app.getConfig().getSync().getQuietHoursStart(); + if (timeStart == null) + app.getConfig().getSync().setQuietHoursStart(new Time(22, 30, 0)); TimePickerDialog.newInstance((v2, hourOfDay, minute, second) -> { app.getConfig().getSync().setQuietHoursEnabled(true); app.getConfig().getSync().setQuietHoursEnd(new Time(hourOfDay, minute, second)); @@ -847,7 +853,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { registerCardAllowRegistrationItem.setChecked(true); app.getProfile().setRegistration(REGISTRATION_ENABLED); app.profileSave(); - addCardItem(CARD_REGISTER, 2, getRegisterCardSharedEventsItem()); + addCardItem(CARD_REGISTER, 3, getRegisterCardSharedEventsItem()); refreshMaterialAboutList(); })) .show(); @@ -860,7 +866,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { registerCardAllowRegistrationItem.setChecked(false); app.getProfile().setRegistration(REGISTRATION_DISABLED); app.profileSave(); - removeCardItem(CARD_REGISTER, 2); + removeCardItem(CARD_REGISTER, 3); refreshMaterialAboutList(); MaterialDialog progressDialog = new MaterialDialog.Builder(activity) .title(getString(R.string.settings_register_allow_registration_dialog_disabling_title)) @@ -1058,8 +1064,8 @@ public class SettingsNewFragment extends MaterialAboutFragment { .icon(icon(CommunityMaterial.Icon3.cmd_translate, iconSizeDp, primaryTextOnPrimaryBg)) .setOnClickAction(() -> { new MaterialDialog.Builder(activity) - .title(getString(R.string.settings_about_language_dialog_title)) - .content(getString(R.string.settings_about_language_dialog_text)) + .title(getString(R.string.app_language_dialog_title)) + .content(getString(R.string.app_language_dialog_text)) .items(getString(R.string.language_system), getString(R.string.language_polish), getString(R.string.language_english), getString(R.string.language_german)) .itemsCallbackSingleChoice(app.getConfig().getUi().getLanguage() == null ? 0 : app.getConfig().getUi().getLanguage().equals("pl") ? 1 : app.getConfig().getUi().getLanguage().equals("en") ? 2 : 3, (dialog, itemView, which, text) -> { switch (which) { @@ -1168,9 +1174,9 @@ public class SettingsNewFragment extends MaterialAboutFragment { MaterialAboutList materialAboutList = new MaterialAboutList(); materialAboutList.addCard(getCardWithItems(null, getProfileCard(false))); - materialAboutList.addCard(getCardWithItems(getString(R.string.settings_theme_title_text), getThemeCard(false))); - materialAboutList.addCard(getCardWithItems(getString(R.string.settings_sync_title_text), getSyncCard(false))); - materialAboutList.addCard(getCardWithItems(getString(R.string.settings_about_register_title_text), getRegisterCard(false))); + materialAboutList.addCard(getCardWithItems(getString(R.string.settings_card_theme_title), getThemeCard(false))); + materialAboutList.addCard(getCardWithItems(getString(R.string.settings_card_sync_title), getSyncCard(false))); + materialAboutList.addCard(getCardWithItems(getString(R.string.settings_card_register_title), getRegisterCard(false))); //if (configurableEndpoints != null) // materialAboutList.addCard(getCardWithItems(getString(R.string.settings_sync_customize_title_text), getSyncCustomizeCard(false))); materialAboutList.addCard(getCardWithItems(null, getAboutCard(false), true)); diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsUtil.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsUtil.kt new file mode 100644 index 00000000..5ed3fb5d --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsUtil.kt @@ -0,0 +1,188 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-17. + */ + +package pl.szczodrzynski.edziennik.ui.modules.settings + +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory +import androidx.core.graphics.drawable.toBitmap +import com.danielstone.materialaboutlibrary.items.* +import com.danielstone.materialaboutlibrary.model.MaterialAboutCard +import com.mikepenz.iconics.IconicsDrawable +import com.mikepenz.iconics.typeface.IIcon +import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial +import com.mikepenz.iconics.utils.colorInt +import com.mikepenz.iconics.utils.sizeDp +import pl.szczodrzynski.edziennik.MainActivity +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.after +import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.utils.Colors +import pl.szczodrzynski.edziennik.utils.Themes + +class SettingsUtil( + val activity: MainActivity, + private val onRefresh: () -> Unit +) { + + fun refresh() = onRefresh() + + private fun IIcon.asDrawable(color: Int? = null, size: Int = 20) = IconicsDrawable(activity).apply { + icon = this@asDrawable + sizeDp = size + colorInt = color ?: Themes.getPrimaryTextColor(activity) + } + + fun createCard( + titleRes: Int?, + items: List, + itemsMore: List, + backgroundColor: Int? = null, + theme: Int? = null + ): MaterialAboutCard { + val card = MaterialAboutCard.Builder() + .title(titleRes ?: 0) + .cardColor(backgroundColor ?: 0) + .theme(theme ?: 0) + .build() + card.items.addAll(items) + + if (itemsMore.isNotEmpty()) { + card.items.add(createMoreItem(card, itemsMore)) + } + + return card + } + + fun createMoreItem( + card: MaterialAboutCard, + items: List + ): MaterialAboutActionItem { + val iconColor = card.cardColor.let { + if (it == 0) + null + else + Colors.legibleTextColor(it) + } + + val moreItem = MaterialAboutActionItem.Builder() + .text(R.string.settings_more_text) + .icon(CommunityMaterial.Icon.cmd_chevron_down.asDrawable(iconColor, size = 14)) + .build() + + moreItem.setOnClickAction { + card.items.after(moreItem, items) + card.items.remove(moreItem) + onRefresh() + } + + return moreItem + } + + fun createSectionItem(text: Int) = MaterialAboutSectionItem(text) + + fun createActionItem( + text: Int, + subText: Int? = null, + icon: IIcon, + backgroundColor: Int? = null, + onClick: (item: MaterialAboutActionItem) -> Unit + ): MaterialAboutActionItem { + val iconColor = backgroundColor?.let { Colors.legibleTextColor(it) } + + val item = MaterialAboutActionItem.Builder() + .text(text) + .subText(subText ?: 0) + .icon(icon.asDrawable(iconColor)) + .build() + + item.setOnClickAction { + onClick(item) + } + + return item + } + + fun createPropertyItem( + text: Int, + subText: Int? = null, + subTextChecked: Int? = null, + icon: IIcon, + backgroundColor: Int? = null, + value: Boolean, + beforeChange: ((item: MaterialAboutSwitchItem, value: Boolean) -> Boolean)? = null, + onChange: (item: MaterialAboutSwitchItem, value: Boolean) -> Unit + ): MaterialAboutSwitchItem { + val iconColor = backgroundColor?.let { Colors.legibleTextColor(it) } + + val item = MaterialAboutSwitchItem.Builder() + .text(text) + .subText(subText ?: 0) + .subTextChecked(subTextChecked ?: 0) + .icon(icon.asDrawable(iconColor)) + .setChecked(value) + .build() + + item.setOnCheckedChangedAction { item, isChecked -> + if (beforeChange?.invoke(item as MaterialAboutSwitchItem, isChecked) == false) + return@setOnCheckedChangedAction false + onChange(item as MaterialAboutSwitchItem, isChecked) + true + } + + return item + } + + fun createPropertyActionItem( + text: Int, + subText: Int? = null, + subTextChecked: Int? = null, + icon: IIcon, + backgroundColor: Int? = null, + value: Boolean, + onChange: (item: MaterialAboutActionSwitchItem, value: Boolean) -> Unit, + onClick: (item: MaterialAboutActionSwitchItem) -> Unit + ): MaterialAboutSwitchItem { + val iconColor = backgroundColor?.let { Colors.legibleTextColor(it) } + + val item = MaterialAboutActionSwitchItem.Builder() + .text(text) + .subText(subText ?: 0) + .subTextChecked(subTextChecked ?: 0) + .icon(icon.asDrawable(iconColor)) + .setChecked(value) + .build() + + item.setOnClickAction { + onClick(item) + } + item.setOnCheckedChangedAction { item, isChecked -> + onChange(item as MaterialAboutActionSwitchItem, isChecked) + true + } + + return item + } + + fun createTitleItem(): MaterialAboutTitleItem = + MaterialAboutTitleItem.Builder() + .text(R.string.app_name) + .desc(R.string.settings_about_title_subtext) + .icon(R.mipmap.ic_splash) + .build() + + fun createProfileItem(profile: Profile, onClick: (profile: Profile) -> Unit) = + MaterialAboutProfileItem( + MaterialAboutTitleItem.Builder() + .text(profile.name) + .desc(profile.subname) + .icon(RoundedBitmapDrawableFactory.create( + activity.resources, + profile.getImageDrawable(activity).toBitmap() + ).also { + it.isCircular = true + }) + .setOnClickAction { onClick(profile) } + .build() + ) +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsViewTypeManager.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsViewTypeManager.kt new file mode 100644 index 00000000..1fb14fcd --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsViewTypeManager.kt @@ -0,0 +1,46 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-17. + */ + +package pl.szczodrzynski.edziennik.ui.modules.settings + +import android.content.Context +import android.view.View +import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder +import com.danielstone.materialaboutlibrary.items.MaterialAboutItem +import com.danielstone.materialaboutlibrary.items.MaterialAboutTitleItem.MaterialAboutTitleItemViewHolder +import com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsViewTypeManager.ItemType.Companion.PROFILE_ITEM + +class SettingsViewTypeManager : DefaultViewTypeManager() { + class ItemType { + companion object { + const val PROFILE_ITEM = 10 + } + } + + override fun getLayout(itemType: Int) = when (itemType) { + PROFILE_ITEM -> R.layout.mal_material_about_profile_item + else -> super.getLayout(itemType) + } + + override fun getViewHolder(itemType: Int, view: View): MaterialAboutItemViewHolder = + when (itemType) { + PROFILE_ITEM -> MaterialAboutProfileItem.getViewHolder(view) + else -> super.getViewHolder(itemType, view) + } + + override fun setupItem( + itemType: Int, + holder: MaterialAboutItemViewHolder, + item: MaterialAboutItem, + context: Context + ) = when (itemType) { + PROFILE_ITEM -> MaterialAboutProfileItem.setupItem( + holder as MaterialAboutTitleItemViewHolder, + item as MaterialAboutProfileItem, context + ) + else -> super.setupItem(itemType, holder, item, context) + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsAboutCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsAboutCard.kt new file mode 100644 index 00000000..97e4a538 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsAboutCard.kt @@ -0,0 +1,150 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-18. + */ + +package pl.szczodrzynski.edziennik.ui.modules.settings.cards + +import android.content.Intent +import android.media.MediaPlayer +import android.widget.Toast +import com.danielstone.materialaboutlibrary.items.MaterialAboutItem +import com.danielstone.materialaboutlibrary.model.MaterialAboutCard +import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial +import eu.szkolny.font.SzkolnyFont +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.BuildConfig +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.sync.UpdateWorker +import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog +import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsCard +import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsLicenseActivity +import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsUtil +import pl.szczodrzynski.edziennik.utils.Utils +import kotlin.coroutines.CoroutineContext + +class SettingsAboutCard(util: SettingsUtil) : SettingsCard(util), CoroutineScope { + + private val job: Job = Job() + override val coroutineContext: CoroutineContext + get() = job + Dispatchers.Main + + private var clickCounter = 0 + private val mediaPlayer by lazy { + MediaPlayer.create(activity, R.raw.ogarnij_sie) + } + + override fun buildCard(): MaterialAboutCard = + util.createCard( + null, + items = listOf(), + itemsMore = listOf(), + backgroundColor = 0xff1976d2.toInt(), + theme = R.style.AppTheme_Dark + ).also { + it.items.addAll(getItems(it)) + } + + override fun getItems() = listOf() + override fun getItemsMore() = listOf() + + private fun getItems(card: MaterialAboutCard) = listOf( + util.createTitleItem(), + + util.createActionItem( + text = R.string.settings_about_version_text, + icon = CommunityMaterial.Icon2.cmd_information_outline, + onClick = { item -> + clickCounter++ + if (clickCounter < 7) + Toast.makeText(activity, "\uD83D\uDE02", Toast.LENGTH_SHORT).show() + item.subText = + BuildConfig.VERSION_NAME + ", " + BuildConfig.BUILD_TYPE + " \uD83D\uDCA3" + util.refresh() + if (clickCounter >= 7) { + mediaPlayer.start() + clickCounter = 0 + } + } + ).also { + it.subText = BuildConfig.VERSION_NAME + ", " + BuildConfig.BUILD_TYPE + }, + + util.createMoreItem(card, items = listOf( + util.createActionItem( + text = R.string.settings_about_changelog_text, + icon = CommunityMaterial.Icon3.cmd_radar + ) { + ChangelogDialog(activity) + }, + + util.createActionItem( + text = R.string.settings_about_update_text, + subText = R.string.settings_about_update_subtext, + icon = CommunityMaterial.Icon3.cmd_update + ) { + launch { + UpdateWorker.runNow(app) + } + } + )), + + util.createSectionItem( + text = R.string.see_also + ), + + util.createActionItem( + text = R.string.settings_about_privacy_policy_text, + icon = CommunityMaterial.Icon3.cmd_shield_outline + ) { + Utils.openUrl(activity, "https://szkolny.eu/privacy-policy") + }, + + util.createActionItem( + text = R.string.settings_about_discord_text, + subText = R.string.settings_about_discord_subtext, + icon = SzkolnyFont.Icon.szf_discord_outline + ) { + Utils.openUrl(activity, "https://szkolny.eu/discord") + }, + + util.createActionItem( + text = R.string.settings_about_github_text, + subText = R.string.settings_about_github_subtext, + icon = SzkolnyFont.Icon.szf_github_face + ) { + Utils.openUrl(activity, "https://szkolny.eu/github/android") + }, + + util.createMoreItem(card, items = listOfNotNull( + util.createActionItem( + text = R.string.settings_about_homepage_text, + subText = R.string.settings_about_homepage_subtext, + icon = CommunityMaterial.Icon.cmd_earth + ) { + Utils.openUrl(activity, "https://szkolny.eu/") + }, + + util.createActionItem( + text = R.string.settings_about_licenses_text, + icon = CommunityMaterial.Icon.cmd_code_braces + ) { + activity.startActivity(Intent(activity, SettingsLicenseActivity::class.java)) + }, + + if (App.devMode) + util.createActionItem( + text = R.string.settings_about_crash_text, + subText = R.string.settings_about_crash_subtext, + icon = CommunityMaterial.Icon.cmd_bug_outline + ) { + throw RuntimeException("MANUAL CRASH") + } + else + null + )) + ) +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsProfileCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsProfileCard.kt new file mode 100644 index 00000000..a783731f --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsProfileCard.kt @@ -0,0 +1,59 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-18. + */ + +package pl.szczodrzynski.edziennik.ui.modules.settings.cards + +import android.content.Intent +import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial +import eu.szkolny.font.SzkolnyFont +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog +import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity +import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsCard +import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsUtil + +class SettingsProfileCard(util: SettingsUtil) : SettingsCard(util) { + + override fun buildCard() = util.createCard( + null, + items = getItems(), + itemsMore = getItemsMore() + ) + + override fun getItems() = listOf( + util.createProfileItem( + profile = app.profile + ) { + + }, + + util.createActionItem( + text = R.string.settings_add_student_text, + subText = R.string.settings_add_student_subtext, + icon = CommunityMaterial.Icon.cmd_account_plus_outline + ) { + activity.startActivity(Intent(activity, LoginActivity::class.java)) + }, + + util.createActionItem( + text = R.string.settings_profile_remove_text, + subText = R.string.settings_profile_remove_subtext, + icon = SzkolnyFont.Icon.szf_delete_empty_outline + ) { + ProfileRemoveDialog(activity, app.profile.id, app.profile.name, false) + } + ) + + override fun getItemsMore() = listOf( + util.createPropertyItem( + text = R.string.settings_profile_sync_text, + subText = R.string.settings_profile_sync_subtext, + icon = CommunityMaterial.Icon.cmd_account_convert, + value = app.profile.syncEnabled, + ) { _, it -> + app.profile.syncEnabled = it + app.profileSave() + } + ) +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsRegisterCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsRegisterCard.kt new file mode 100644 index 00000000..14afd0cb --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsRegisterCard.kt @@ -0,0 +1,152 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-18. + */ + +package pl.szczodrzynski.edziennik.ui.modules.settings.cards + +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial +import eu.szkolny.font.SzkolnyFont +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.after +import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_LIBRUS +import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.REGISTRATION_ENABLED +import pl.szczodrzynski.edziennik.ui.dialogs.bell.BellSyncConfigDialog +import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradesConfigDialog +import pl.szczodrzynski.edziennik.ui.dialogs.settings.AttendanceConfigDialog +import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegistrationConfigDialog +import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsCard +import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsUtil + +class SettingsRegisterCard(util: SettingsUtil) : SettingsCard(util) { + + override fun buildCard() = util.createCard( + R.string.settings_card_register_title, + items = getItems(), + itemsMore = getItemsMore() + ) + + private fun getBellSync() = + configGlobal.timetable.bellSyncDiff?.let { + activity.getString( + R.string.settings_register_bell_sync_subtext_format, + (if (configGlobal.timetable.bellSyncMultiplier == -1) "-" else "+") + it.stringHMS + ) + } ?: activity.getString(R.string.settings_register_bell_sync_subtext_disabled) + + private val sharedEventsItem by lazy { + util.createPropertyItem( + text = R.string.settings_register_shared_events_text, + subText = R.string.settings_register_shared_events_subtext, + icon = CommunityMaterial.Icon3.cmd_share_outline, + value = app.profile.enableSharedEvents + ) { _, value -> + app.profile.enableSharedEvents = value + app.profileSave() + MaterialAlertDialogBuilder(activity) + .setTitle(R.string.event_sharing) + .setMessage( + if (value) + R.string.settings_register_shared_events_dialog_enabled_text + else + R.string.settings_register_shared_events_dialog_disabled_text + ) + .setPositiveButton(R.string.ok, null) + .show() + } + } + + override fun getItems() = listOfNotNull( + util.createActionItem( + text = R.string.menu_grades_config, + icon = CommunityMaterial.Icon3.cmd_numeric_5_box_outline + ) { + GradesConfigDialog(activity, reloadOnDismiss = false) + }, + + util.createActionItem( + text = R.string.menu_attendance_config, + icon = CommunityMaterial.Icon.cmd_calendar_remove_outline + ) { + AttendanceConfigDialog(activity, reloadOnDismiss = false) + }, + + util.createPropertyItem( + text = R.string.settings_register_allow_registration_text, + subText = R.string.settings_register_allow_registration_subtext, + icon = CommunityMaterial.Icon.cmd_account_circle_outline, + value = app.profile.registration == REGISTRATION_ENABLED, + beforeChange = { item, value -> + if (app.profile.registration == REGISTRATION_ENABLED == value) + // allow the switch to change - needed for util.refresh() to change the visual state + return@createPropertyItem true + val dialog = + RegistrationConfigDialog(activity, app.profile, onChangeListener = { enabled -> + if (item.isChecked == enabled) + return@RegistrationConfigDialog + item.isChecked = enabled + if (value) { + card.items.after(item, sharedEventsItem) + } else { + card.items.remove(sharedEventsItem) + } + util.refresh() + }) + if (value) + dialog.showEnableDialog() + else + dialog.showDisableDialog() + false + } + ) { _, _ -> }, + + if (app.profile.registration == REGISTRATION_ENABLED) + sharedEventsItem + else + null + ) + + override fun getItemsMore() = listOfNotNull( + util.createActionItem( + text = R.string.settings_register_bell_sync_text, + icon = SzkolnyFont.Icon.szf_alarm_bell_outline, + onClick = { + BellSyncConfigDialog(activity, onChangeListener = { + it.subText = getBellSync() + util.refresh() + }) + } + ).also { + it.subText = getBellSync() + }, + + util.createPropertyItem( + text = R.string.settings_register_count_in_seconds_text, + subText = R.string.settings_register_count_in_seconds_subtext, + icon = CommunityMaterial.Icon3.cmd_timer_outline, + value = configGlobal.timetable.countInSeconds + ) { _, it -> + configGlobal.timetable.countInSeconds = it + }, + + if (app.profile.loginStoreType == LOGIN_TYPE_LIBRUS) + util.createPropertyItem( + text = R.string.settings_register_show_teacher_absences_text, + icon = CommunityMaterial.Icon.cmd_account_arrow_right_outline, + value = app.profile.getStudentData("showTeacherAbsences", true) + ) { _, it -> + app.profile.putStudentData("showTeacherAbsences", it) + app.profileSave() + } + else + null, + + util.createPropertyItem( + text = R.string.settings_register_hide_sticks_from_old, + icon = CommunityMaterial.Icon3.cmd_numeric_1_box_outline, + value = configProfile.grades.hideSticksFromOld + ) { _, it -> + configProfile.grades.hideSticksFromOld = it + } + ) +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsSyncCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsSyncCard.kt new file mode 100644 index 00000000..1d42b86b --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsSyncCard.kt @@ -0,0 +1,200 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-18. + */ + +package pl.szczodrzynski.edziennik.ui.modules.settings.cards + +import android.content.Intent +import android.content.Intent.FLAG_ACTIVITY_NEW_TASK +import android.net.Uri +import android.os.Build.VERSION.SDK_INT +import android.os.Build.VERSION_CODES +import android.provider.Settings +import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial +import pl.szczodrzynski.edziennik.MainActivity +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.after +import pl.szczodrzynski.edziennik.getSyncInterval +import pl.szczodrzynski.edziennik.sync.SyncWorker +import pl.szczodrzynski.edziennik.sync.UpdateWorker +import pl.szczodrzynski.edziennik.ui.dialogs.sync.NotificationFilterDialog +import pl.szczodrzynski.edziennik.ui.dialogs.sync.QuietHoursConfigDialog +import pl.szczodrzynski.edziennik.ui.dialogs.sync.SyncIntervalDialog +import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsCard +import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsUtil +import pl.szczodrzynski.edziennik.utils.models.Time + +class SettingsSyncCard(util: SettingsUtil) : SettingsCard(util) { + + override fun buildCard() = util.createCard( + R.string.settings_card_sync_title, + items = getItems(), + itemsMore = getItemsMore() + ) + + private fun getQuietHours(): String { + if (configGlobal.sync.quietHoursStart == null) { + configGlobal.sync.quietHoursStart = Time(22, 30, 0) + } + if (configGlobal.sync.quietHoursEnd == null) { + configGlobal.sync.quietHoursEnd = Time(6, 30, 0) + } + + return activity.getString( + if (configGlobal.sync.quietHoursStart!! > configGlobal.sync.quietHoursEnd!!) + R.string.settings_sync_quiet_hours_subtext_next_day_format + else + R.string.settings_sync_quiet_hours_subtext_format, + configGlobal.sync.quietHoursStart?.stringHM, + configGlobal.sync.quietHoursEnd?.stringHM + ) + } + + private val syncWifiItem by lazy { + util.createPropertyItem( + text = R.string.settings_sync_wifi_text, + subText = R.string.settings_sync_wifi_subtext, + icon = CommunityMaterial.Icon3.cmd_wifi_strength_2, + value = configGlobal.sync.onlyWifi + ) { _, it -> + configGlobal.sync.onlyWifi = it + SyncWorker.rescheduleNext(app) + } + } + + override fun getItems() = listOfNotNull( + util.createPropertyActionItem( + text = R.string.settings_sync_sync_interval_text, + subText = R.string.settings_sync_sync_interval_subtext_disabled, + icon = CommunityMaterial.Icon.cmd_download_outline, + value = configGlobal.sync.enabled, + onChange = { item, value -> + // When calling onChange from the onClick listener below + // a list refresh is requested, the adapter refreshes + // all view holders, changing the state of the switch + // view, thus calling onChange again, causing it to + // try to recursively refresh the list, therefore + // crashing the app. To avoid this, the method will + // continue only if the checked state is different + // from the saved value, which should only happen + // when clicking the switch manually or when called + // by onClick, **once** (because onClick doesn't + // update the config value - we let the switch + // listener do it). Then there comes a different problem, + // when onClick changes the subText and the onChange + // listener returns because the boolean value + // is unchanged, leaving the list not refreshed. + // To solve this, a list refresh is also requested + // in onClick, when the config value is the same + // as the new switch value, which would normally + // cause the onChange method to exit here. + if (value == configGlobal.sync.enabled) + return@createPropertyActionItem + + if (value) { + card.items.after(item, syncWifiItem) + } else { + card.items.remove(syncWifiItem) + } + util.refresh() + + configGlobal.sync.enabled = value + SyncWorker.rescheduleNext(app) + }, + onClick = { item -> + SyncIntervalDialog(activity, onChangeListener = { + item.subTextChecked = activity.getSyncInterval(configGlobal.sync.interval) + item.isChecked = true + item.onCheckedChangedAction.onCheckedChanged(item, true) + if (configGlobal.sync.enabled) + util.refresh() + }) + } + ).also { + it.subTextChecked = activity.getSyncInterval(configGlobal.sync.interval) + }, + + if (configGlobal.sync.enabled) + syncWifiItem + else + null, + + util.createActionItem( + text = R.string.settings_profile_notifications_text, + subText = R.string.settings_profile_notifications_subtext, + icon = CommunityMaterial.Icon2.cmd_filter_outline + ) { + NotificationFilterDialog(activity) + }, + + util.createPropertyActionItem( + text = R.string.settings_sync_quiet_hours_text, + subText = R.string.settings_sync_quiet_hours_subtext_disabled, + icon = CommunityMaterial.Icon.cmd_bell_sleep_outline, + value = configGlobal.sync.quietHoursEnabled, + onChange = { _, value -> + configGlobal.sync.quietHoursEnabled = value + }, + onClick = { item -> + QuietHoursConfigDialog(activity, onChangeListener = { + item.subTextChecked = getQuietHours() + item.isChecked = configGlobal.sync.quietHoursEnabled + util.refresh() + }) + } + ).also { + it.subTextChecked = getQuietHours() + }, + + util.createActionItem( + text = R.string.settings_sync_web_push_text, + subText = R.string.settings_sync_web_push_subtext, + icon = CommunityMaterial.Icon2.cmd_laptop + ) { + activity.loadTarget(MainActivity.TARGET_WEB_PUSH) + } + ) + + override fun getItemsMore() = listOfNotNull( + util.createPropertyItem( + text = R.string.settings_sync_updates_text, + icon = CommunityMaterial.Icon.cmd_cellphone_arrow_down, + value = configGlobal.sync.notifyAboutUpdates + ) { _, it -> + configGlobal.sync.notifyAboutUpdates = it + UpdateWorker.rescheduleNext(app) + }, + + if (SDK_INT >= VERSION_CODES.KITKAT) + util.createActionItem( + text = R.string.settings_sync_notifications_settings_text, + subText = R.string.settings_sync_notifications_settings_subtext, + icon = CommunityMaterial.Icon.cmd_cog_outline + ) { + val channel = app.notificationChannelsManager.data.key + val intent = Intent().apply { + when { + SDK_INT >= VERSION_CODES.O -> { + action = Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS + putExtra(Settings.EXTRA_APP_PACKAGE, app.packageName) + putExtra(Settings.EXTRA_CHANNEL_ID, channel) + addFlags(FLAG_ACTIVITY_NEW_TASK) + } + SDK_INT >= VERSION_CODES.LOLLIPOP -> { + action = "android.settings.APP_NOTIFICATION_SETTINGS" + putExtra("app_package", app.packageName) + putExtra("app_uid", app.applicationInfo.uid) + } + else -> { + action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS + addCategory(Intent.CATEGORY_DEFAULT) + data = Uri.parse("package:" + app.packageName) + } + } + } + activity.startActivity(intent) + } + else + null + ) +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsThemeCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsThemeCard.kt new file mode 100644 index 00000000..0cb710cb --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsThemeCard.kt @@ -0,0 +1,96 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-18. + */ + +package pl.szczodrzynski.edziennik.ui.modules.settings.cards + +import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.ui.dialogs.settings.AppLanguageDialog +import pl.szczodrzynski.edziennik.ui.dialogs.settings.MiniMenuConfigDialog +import pl.szczodrzynski.edziennik.ui.dialogs.settings.ThemeChooserDialog +import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsCard +import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsUtil +import pl.szczodrzynski.edziennik.utils.Themes +import pl.szczodrzynski.edziennik.utils.models.Date + +class SettingsThemeCard(util: SettingsUtil) : SettingsCard(util) { + + override fun buildCard() = util.createCard( + R.string.settings_card_theme_title, + items = getItems(), + itemsMore = getItemsMore() + ) + + override fun getItems() = listOfNotNull( + if (Date.getToday().month % 11 == 1) // cool math games + util.createPropertyItem( + text = R.string.settings_theme_snowfall_text, + subText = R.string.settings_theme_snowfall_subtext, + icon = CommunityMaterial.Icon3.cmd_snowflake, + value = configGlobal.ui.snowfall + ) { _, it -> + configGlobal.ui.snowfall = it + activity.recreate() + } + else null, + + util.createActionItem( + text = R.string.settings_theme_theme_text, + subText = Themes.getThemeNameRes(), + icon = CommunityMaterial.Icon3.cmd_palette_outline + ) { + ThemeChooserDialog(activity) + }, + + util.createActionItem( + text = R.string.settings_about_language_text, + subText = R.string.settings_about_language_subtext, + icon = CommunityMaterial.Icon3.cmd_translate + ) { + AppLanguageDialog(activity) + }, + + util.createPropertyItem( + text = R.string.settings_theme_mini_drawer_text, + subText = R.string.settings_theme_mini_drawer_subtext, + icon = CommunityMaterial.Icon.cmd_dots_vertical, + value = configGlobal.ui.miniMenuVisible + ) { _, it -> + configGlobal.ui.miniMenuVisible = it + activity.navView.drawer.miniDrawerVisiblePortrait = it + } + ) + + override fun getItemsMore() = listOf( + util.createActionItem( + text = R.string.settings_theme_mini_drawer_buttons_text, + icon = CommunityMaterial.Icon2.cmd_format_list_checks + ) { + MiniMenuConfigDialog(activity) + }, + + util.createActionItem( + text = R.string.settings_theme_drawer_header_text, + icon = CommunityMaterial.Icon2.cmd_image_outline + ) { + // TODO: 2021-03-17 + }, + + util.createActionItem( + text = R.string.settings_theme_app_background_text, + subText = R.string.settings_theme_app_background_subtext, + icon = CommunityMaterial.Icon2.cmd_image_filter_hdr + ) { + // TODO: 2021-03-17 + }, + + util.createPropertyItem( + text = R.string.settings_theme_open_drawer_on_back_pressed_text, + icon = CommunityMaterial.Icon3.cmd_menu_open, + value = configGlobal.ui.openDrawerOnBackPressed + ) { _, it -> + configGlobal.ui.openDrawerOnBackPressed = it + } + ) +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/Themes.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/Themes.kt index e2189f71..5f62b794 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/Themes.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/Themes.kt @@ -42,6 +42,12 @@ object Themes { theme = themeList[value] } + var themeIndex + get() = themeList.indexOf(theme) + set(value) { + theme = themeList[value] + } + val appThemeNoDisplay: Int get() = if (theme.isDark) R.style.AppTheme_Dark_NoDisplay else R.style.AppTheme_Light_NoDisplay @@ -61,38 +67,15 @@ object Themes { return getColorFromAttr(context, android.R.attr.textColorSecondary) } - /*public static int getChipColorRes() { - switch (themeInt) { - case THEME_LIGHT: - return R.color.chipBackgroundLight; - default: - case THEME_DARK: - return R.color.chipBackgroundDark; - case THEME_BLACK: - return R.color.chipBackgroundBlack; - case THEME_CHOCOLATE: - return R.color.chipBackgroundChocolate; - case THEME_BLUE: - return R.color.chipBackgroundBlue; - case THEME_PURPLE: - return R.color.chipBackgroundPurple; - case THEME_GREEN: - return R.color.chipBackgroundGreen; - case THEME_AMBER: - return R.color.chipBackgroundAmber; - case THEME_RED: - return R.color.chipBackgroundRed; - } - }*/ fun getThemeName(context: Context): String { return context.getString(theme.name) } - fun getThemeNames(context: Context): List { - val list = mutableListOf() - for (theme in themeList) { - list += context.getString(theme.name) + @StringRes + fun getThemeNameRes() = theme.name + + fun getThemeNames(context: Context) = + themeList.map { + context.getString(it.name) } - return list - } } diff --git a/app/src/main/res/layout/dialog_edit_text.xml b/app/src/main/res/layout/dialog_edit_text.xml new file mode 100644 index 00000000..6937705e --- /dev/null +++ b/app/src/main/res/layout/dialog_edit_text.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + diff --git a/app/src/main/res/layout/mal_material_about_profile_item.xml b/app/src/main/res/layout/mal_material_about_profile_item.xml new file mode 100644 index 00000000..e1802130 --- /dev/null +++ b/app/src/main/res/layout/mal_material_about_profile_item.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 6e37bf58..9949f2e2 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -351,8 +351,6 @@ Hinzugefügt %1$s%3$s {cmd-share-variant} %1$s von %2$s%3$s {cmd-share-variant} %1$s von Ihnen%3$s - Um das Ereignis freigeben zu können, müssen Sie die Serverregistrierungsoption aktivieren. Auf diese Weise können Sie Ereignisse erstellen und empfangen, die in Ihrer Klasse geteilt werden.\n\nWenn Sie auf OK klicken, wird diese automatisch aktiviert.\n\nStellen Sie sicher, dass Sie die Bedingungen lesen und akzeptieren. - Ereignisse teilen Ereignis entfernen… Ereignis speichern… Ereignis teilen… @@ -830,9 +828,13 @@ etzt bewerten Zeigen Sie, dass Ihnen Szkolny.eu gefällt - bewerten Sie die App und machen Sie sie noch besser! Aktualisieren - Die Registrierung erfolgt automatisch, wenn diese Option aktiviert ist. Sie können Ereignisse erstellen und empfangen, die mit anderen Schülern in Ihrer Klasse geteilt werden. Dank dessen können Sie Elemente, die nicht vom Lehrer gespeichert wurden, zum Klassenbuch hinzufügen.\n\nStellen Sie sicher, dass Sie die Bestimmungen der Datenschutzrichtlinie lesen und die Bestimmungen akzeptieren. - Server-Registrierung - Gemeinsame Ereignisse herunterladen… + Benutzerregistrierung aufheben… + Einige Funktionen wie Ereignisfreigabe oder Benachrichtigungsweiterleitung können nicht mehr verwendet werden.\n\nDie Funktion kann je nach ausgewähltem Profil aktiviert / deaktiviert werden. + Gemeinsame Ereignisse herunterladen… + Die Registrierung erfolgt automatisch, wenn diese Option aktiviert ist. Sie können Ereignisse erstellen und empfangen, die mit anderen Schülern in Ihrer Klasse geteilt werden. Dank dessen können Sie Elemente, die nicht vom Lehrer gespeichert wurden, zum Klassenbuch hinzufügen.\n\nStellen Sie sicher, dass Sie die Bestimmungen der Datenschutzrichtlinie lesen und die Bestimmungen akzeptieren. + Um das Ereignis freigeben zu können, müssen Sie die Serverregistrierungsoption aktivieren. Auf diese Weise können Sie Ereignisse erstellen und empfangen, die in Ihrer Klasse geteilt werden.\n\nWenn Sie auf OK klicken, wird diese automatisch aktiviert.\n\nStellen Sie sicher, dass Sie die Bedingungen lesen und akzeptieren. + Ereignisse teilen + Szkolny.eu Server-Registrierung Löschen gelöschtet Melden @@ -847,13 +849,13 @@ Klicken Sie hier, um eine unerwartete Ausnahme auszulösen Treten Sie unserem Discord-Server bei! Discord Server - Hinweis. Diese Option funktioniert möglicherweise auf einigen Geräten und in einigen Teilen der App nicht. - App-Sprache ändern + Hinweis. Diese Option funktioniert möglicherweise auf einigen Geräten und in einigen Teilen der App nicht. + App-Sprache ändern Deutsch Sprache der App Open-Source-Lizenzen Datenschutzrichtlinie - E-Klassenbuch + E-Klassenbuch © Kuba Szczodrzyński && Kacper Ziubryniewicz\nSeptember 2018 - Februar 2021 Klicken Sie hier, um nach Aktualisierungen zu suchen Aktualisierung @@ -944,7 +946,7 @@ Deaktiviert Daten alle %s herunterladen Automatische Synchronisierung - Synchronisation und Benachrichtigungen + Synchronisation und Benachrichtigungen Über App-Aktualisierungen benachrichtigen Benachrichtigungen auf Ihrem PC anzeigen Benachrichtigungsweiterleitung @@ -968,7 +970,7 @@ Rosa System Thema - Aussehen + Aussehen Teilen Teilen über… Daten Teilen… diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index ab80b93c..2f5cb1fe 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -351,8 +351,6 @@ Adde %1$s%3$s {cmd-share-variant} %1$s by %2$s%3$s {cmd-share-variant} %1$s by you%3$s - You need to turn on server registration, in order to share an event. This option lets you create and receive shared events in your class.\n\nIt will be turned on automatically by pressing OK.\n\nBefore turning it on, make sure you\'ve read the terms and accept them - Sharing events Removing event… Saving event… Sharing event… @@ -832,9 +830,13 @@ Rate now Show that you like Szkolny.eu - rate the app and make it even better! Refresh - Registration is automatic if this option is enabled. It allows you to create and receive events shared with other students in your class. Thanks to this, you can add items not saved by the teacher to the journal.\n\nMake sure you read the terms and accept them. - Server registration - Syncing shared events… + Unregistering the user… + You won\'t be able to use some functions anymore, like Event sharing and Notification forwarding.\n\nThis feature may be enabled/disabled depending on the active profile. + Syncing shared events… + Registration is automatic if this option is enabled. It allows you to create and receive events shared with other students in your class. Thanks to this, you can add items not saved by the teacher to the journal.\n\nContinuing means reading and accepting the Privacy policy. + You need to turn on server registration, in order to share an event. This option lets you create and receive shared events in your class.\n\nIt will be turned on automatically by pressing OK.\n\nContinuing means reading and accepting the Privacy policy. + Sharing events + Szkolny.eu server registration Remove Removed Report @@ -849,13 +851,13 @@ Click to throw an unexpected exception Join our Discord community! Discord server - Notice. This feature may not work on some devices or in some parts of the app. - Change app language - "English " + Notice. This feature may not work on some devices or in some parts of the app. + Change app language + English App language Open-source licenses Privacy policy - E-register + E-register © Kuba Szczodrzyński && Kacper Ziubryniewicz\nSeptember 2018 - February 2021 Click to check for updates Update @@ -946,7 +948,7 @@ Disabled Download data every %s Automatic sync - Sync & notifications + Sync & notifications Notify about app updates Show notifications on your PC Notification forwarding @@ -970,7 +972,7 @@ Pink System Theme - Appearance + Appearance Share Share… Sharing events… diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0ea45e49..9251f4b4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -386,8 +386,6 @@ Dodano %1$s%3$s {cmd-share-variant} %1$s przez %2$s%3$s {cmd-share-variant} %1$s przez Ciebie%3$s - Aby móc udostępnić wydarzenie, należy włączyć opcję rejestracji na serwerze. Pozwala to na tworzenie i odbieranie wydarzeń udostępnionych w Twojej klasie.\n\nPo kliknięciu OK zostanie ona automatycznie włączona.\n\nUpewnij się, że zapoznałeś się z warunkami i akceptujesz jej postanowienia. - Udostępnianie wydarzeń Usuwam wydarzenie… Zapisuję wydarzenie… Udostępniam wydarzenie… @@ -895,9 +893,13 @@ Oceń teraz Pokaż, że podoba ci się Szkolny.eu - oceń aplikację i spraw, by była jeszcze lepsza! Odśwież - Rejestracja jest automatyczna, jeśli ta opcja jest włączona. Pozwala na tworzenie i odbieranie wydarzeń udostępnionych innym uczniom z Twojej klasy. Dzięki temu, można dodawać do dziennika pozycje nie zapisane przez nauczyciela.\n\nUpewnij się, że zapoznałeś się z warunkami Polityki prywatności i akceptujesz jej postanowienia. - Rejestracja na serwerze - Pobieranie udostępnionych wydarzeń… + Trwa wyrejestrowywanie użytkownika… + Stracisz możliwość korzystania z niektórych funkcji, takich jak Udostępnianie wydarzeń czy Przekazywanie powiadomień.\n\nFunkcja może być włączona/wyłączona w zależności od wybranego profilu. + Pobieranie udostępnionych wydarzeń… + Rejestracja jest automatyczna, jeśli ta opcja jest włączona. Pozwala na tworzenie i odbieranie wydarzeń udostępnionych innym uczniom z Twojej klasy. Dzięki temu, można dodawać do dziennika pozycje nie zapisane przez nauczyciela.\n\nKontynuując, oświadczasz przeczytanie i akceptację postanowień Polityki prywatności. + Aby móc udostępnić wydarzenie, należy włączyć opcję rejestracji na serwerze. Pozwala to na tworzenie i odbieranie wydarzeń udostępnionych w Twojej klasie.\n\nPo kliknięciu OK zostanie ona automatycznie włączona.\n\nKontynuując, oświadczasz przeczytanie i akceptację postanowień Polityki prywatności. + Udostępnianie wydarzeń + Rejestracja aplikacji Szkolny.eu Usuń Usunięto Zgłoś @@ -912,13 +914,13 @@ Kliknij, aby wywołać nieoczekiwany wyjątek Dołącz do naszego serwera Discord! Serwer Discord - Uwaga. Ta opcja może nie działać na niektórych urządzeniach oraz w niektórych fragmentach aplikacji. - Zmień język aplikacji + Uwaga. Ta opcja może nie działać na niektórych urządzeniach oraz w niektórych fragmentach aplikacji. + Zmień język aplikacji Polski Język aplikacji Licencje open-source Polityka prywatności - E-dziennik + E-dziennik © Kuba Szczodrzyński && Kacper Ziubryniewicz\nwrzesień 2018 - luty 2021 Kliknij, aby sprawdzić aktualizacje Aktualizacja @@ -1011,7 +1013,7 @@ Wyłączona Pobieraj dane co %s Synchronizacja automatyczna - Synchronizacja i powiadomienia + Synchronizacja i powiadomienia Powiadamiaj o aktualizacjach aplikacji Pokazuj powiadomienia na swoim komputerze Przekazywanie powiadomień @@ -1035,7 +1037,7 @@ Różowy Systemowy Motyw - Wygląd + Wygląd Udostępnij Udostępnij przez… Udostępnianie danych… @@ -1387,4 +1389,10 @@ {cmd-android-studio} Wersja deweloperska \??? Szkoda, opinie innych pomagają mi rozwijać aplikację. + Nie znaleziono profilu ucznia. + Zobacz także + Wejdź na stronę aplikacji + Uzyskaj pomoc lub wesprzyj autorów + Kod źródłowy + Pomóż w rozwoju aplikacji na GitHubie From ea7b4438e8f7e937218e7696a430e0c6d1f8df90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Tue, 23 Mar 2021 15:50:27 +0100 Subject: [PATCH 021/113] [Refactor] Remove unused class and resources. --- .../edziennik/utils/SnackbarHelper.java | 28 ------------------- .../bg_rounded_ripple_4dp_pressed.xml | 8 ------ app/src/main/res/drawable/bg_snackbar.xml | 5 ---- 3 files changed, 41 deletions(-) delete mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/utils/SnackbarHelper.java delete mode 100644 app/src/main/res/drawable/bg_rounded_ripple_4dp_pressed.xml delete mode 100644 app/src/main/res/drawable/bg_snackbar.xml diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/SnackbarHelper.java b/app/src/main/java/pl/szczodrzynski/edziennik/utils/SnackbarHelper.java deleted file mode 100644 index 3fe2648b..00000000 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/SnackbarHelper.java +++ /dev/null @@ -1,28 +0,0 @@ -package pl.szczodrzynski.edziennik.utils; - -import android.content.Context; -import android.view.ViewGroup; - -import com.google.android.material.snackbar.Snackbar; - -import androidx.core.view.ViewCompat; -import pl.szczodrzynski.edziennik.R; - -public class SnackbarHelper { - - public static void configSnackbar(Context context, Snackbar snack) { - addMargins(snack); - setRoundBordersBg(context, snack); - ViewCompat.setElevation(snack.getView(), 6f); - } - - private static void addMargins(Snackbar snack) { - ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) snack.getView().getLayoutParams(); - params.setMargins(12, 12, 12, 12); - snack.getView().setLayoutParams(params); - } - - private static void setRoundBordersBg(Context context, Snackbar snackbar) { - snackbar.getView().setBackground(context.getResources().getDrawable(R.drawable.bg_snackbar)); - } -} diff --git a/app/src/main/res/drawable/bg_rounded_ripple_4dp_pressed.xml b/app/src/main/res/drawable/bg_rounded_ripple_4dp_pressed.xml deleted file mode 100644 index aadf2255..00000000 --- a/app/src/main/res/drawable/bg_rounded_ripple_4dp_pressed.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_snackbar.xml b/app/src/main/res/drawable/bg_snackbar.xml deleted file mode 100644 index 91835112..00000000 --- a/app/src/main/res/drawable/bg_snackbar.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file From 3eb99a4bf511040a97aaaa6af650f62601466b4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Wed, 24 Mar 2021 22:41:28 +0100 Subject: [PATCH 022/113] [App] Change companion values to lateinit. --- .../java/pl/szczodrzynski/edziennik/App.kt | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/App.kt b/app/src/main/java/pl/szczodrzynski/edziennik/App.kt index 0bc6f2e0..8fac3da3 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/App.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/App.kt @@ -51,8 +51,8 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope { companion object { @Volatile lateinit var db: AppDb - val config: Config by lazy { Config(db) } - var profile: Profile by mutableLazy { Profile(0, 0, 0, "") } + lateinit var config: Config + lateinit var profile: Profile val profileId get() = profile.id @@ -106,7 +106,7 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope { .readTimeout(30, TimeUnit.SECONDS) builder.installHttpsSupport(this) - if (devMode || BuildConfig.DEBUG) { + if (devMode) { HyperLog.initialize(this) HyperLog.setLogLevel(Log.VERBOSE) HyperLog.setLogFormat(DebugLogFormat(this)) @@ -158,23 +158,25 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope { .errorActivity(CrashActivity::class.java) .apply() Iconics.init(applicationContext) + + // initialize companion object values App.db = AppDb(this) - Themes.themeInt = config.ui.theme - devMode = config.debugMode - MHttp.instance().customOkHttpClient(http) + App.config = Config(App.db) + App.profile = Profile(0, 0, 0, "") + debugMode = BuildConfig.DEBUG + devMode = config.debugMode || debugMode if (!profileLoadById(config.lastProfileId)) { db.profileDao().firstId?.let { profileLoadById(it) } } + MHttp.instance().customOkHttpClient(http) + + Themes.themeInt = config.ui.theme config.ui.language?.let { setLanguage(it) } - debugMode = BuildConfig.DEBUG - if (BuildConfig.DEBUG) - devMode = true - Signing.getCert(this) launch { @@ -183,7 +185,6 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope { if (config.devModePassword != null) checkDevModePassword() - devMode = debugMode || config.debugMode if (config.sync.enabled) SyncWorker.scheduleNext(this@App, false) From 43d71c082bbbbcbf8d66a23d3d191858684f79a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Wed, 24 Mar 2021 23:02:18 +0100 Subject: [PATCH 023/113] [App] Fix internet and SSL connection. --- app/build.gradle | 1 + .../java/pl/szczodrzynski/edziennik/App.kt | 50 ++++++++++++------- .../pl/szczodrzynski/edziennik/Extensions.kt | 43 ---------------- 3 files changed, 33 insertions(+), 61 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 0e83e107..363d5a21 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -119,6 +119,7 @@ dependencies { implementation "eu.szkolny:mhttp:af4b62e6e9" implementation "eu.szkolny:nachos:0e5dfcaceb" implementation "eu.szkolny.selective-dao:annotation:27f8f3f194" + implementation "eu.szkolny:ssl-provider:1.0.0" implementation "pl.szczodrzynski:navlib:0.7.2" implementation "pl.szczodrzynski:numberslidingpicker:2921225f76" implementation "pl.szczodrzynski:recyclertablayout:700f980584" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/App.kt b/app/src/main/java/pl/szczodrzynski/edziennik/App.kt index 8fac3da3..d8a2ec6a 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/App.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/App.kt @@ -26,6 +26,8 @@ import com.google.firebase.messaging.FirebaseMessaging import com.google.gson.Gson import com.hypertrack.hyperlog.HyperLog import com.mikepenz.iconics.Iconics +import eu.szkolny.sslprovider.SSLProvider +import eu.szkolny.sslprovider.enableSupportedTls import im.wangchao.mhttp.MHttp import kotlinx.coroutines.* import me.leolin.shortcutbadger.ShortcutBadger @@ -44,6 +46,7 @@ import pl.szczodrzynski.edziennik.ui.modules.base.CrashActivity import pl.szczodrzynski.edziennik.utils.* import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.managers.* +import timber.log.Timber import java.util.concurrent.TimeUnit import kotlin.coroutines.CoroutineContext @@ -94,17 +97,20 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope { | __ | | | | | | ___/ | | | | | | | | | | |_| |_| |_| |_| |*/ - val http: OkHttpClient by lazy { + lateinit var http: OkHttpClient + lateinit var httpLazy: OkHttpClient + + private fun buildHttp() { val builder = OkHttpClient.Builder() - .cache(null) - .followRedirects(true) - .followSslRedirects(true) - .retryOnConnectionFailure(true) - .cookieJar(cookieJar) - .connectTimeout(15, TimeUnit.SECONDS) - .writeTimeout(10, TimeUnit.SECONDS) - .readTimeout(30, TimeUnit.SECONDS) - builder.installHttpsSupport(this) + .cache(null) + .followRedirects(true) + .followSslRedirects(true) + .retryOnConnectionFailure(true) + .cookieJar(cookieJar) + .connectTimeout(15, TimeUnit.SECONDS) + .writeTimeout(10, TimeUnit.SECONDS) + .readTimeout(30, TimeUnit.SECONDS) + .enableSupportedTls(enableCleartext = true) if (devMode) { HyperLog.initialize(this) @@ -115,13 +121,14 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope { builder.addInterceptor(chuckerInterceptor) } - builder.build() - } - val httpLazy: OkHttpClient by lazy { - http.newBuilder() - .followRedirects(false) - .followSslRedirects(false) - .build() + http = builder.build() + + httpLazy = http.newBuilder() + .followRedirects(false) + .followSslRedirects(false) + .build() + + MHttp.instance().customOkHttpClient(http) } val cookieJar by lazy { DumbCookieJar(this) } @@ -170,7 +177,7 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope { db.profileDao().firstId?.let { profileLoadById(it) } } - MHttp.instance().customOkHttpClient(http) + buildHttp() Themes.themeInt = config.ui.theme config.ui.language?.let { @@ -183,6 +190,13 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope { withContext(Dispatchers.Default) { config.migrate(this@App) + SSLProvider.install(applicationContext, downloadIfNeeded = true, supportTls13 = true, onFinish = { + buildHttp() + }, onError = { + Timber.e("Failed to install SSLProvider: $it") + it.printStackTrace() + }) + if (config.devModePassword != null) checkDevModePassword() diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt index 71febada..d7855364 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt @@ -40,7 +40,6 @@ import androidx.lifecycle.Observer import androidx.recyclerview.widget.RecyclerView import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import androidx.viewpager.widget.ViewPager -import com.google.android.gms.security.ProviderInstaller import com.google.android.material.button.MaterialButton import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.gson.* @@ -50,10 +49,7 @@ import im.wangchao.mhttp.Response import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch -import okhttp3.ConnectionSpec -import okhttp3.OkHttpClient import okhttp3.RequestBody -import okhttp3.TlsVersion import okio.Buffer import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.models.ApiError @@ -63,7 +59,6 @@ import pl.szczodrzynski.edziennik.data.db.entity.Notification import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.data.db.entity.Teacher import pl.szczodrzynski.edziennik.data.db.entity.Team -import pl.szczodrzynski.edziennik.network.TLSSocketFactory import pl.szczodrzynski.edziennik.utils.models.Time import java.io.InterruptedIOException import java.io.PrintWriter @@ -73,17 +68,13 @@ import java.net.ConnectException import java.net.SocketTimeoutException import java.net.UnknownHostException import java.nio.charset.Charset -import java.security.KeyStore import java.security.MessageDigest import java.text.SimpleDateFormat import java.util.* import java.util.zip.CRC32 import javax.crypto.Mac import javax.crypto.spec.SecretKeySpec -import javax.net.ssl.SSLContext import javax.net.ssl.SSLException -import javax.net.ssl.TrustManagerFactory -import javax.net.ssl.X509TrustManager import kotlin.Pair @@ -1107,40 +1098,6 @@ fun Cursor?.getString(columnName: String) = this?.getStringOrNull(getColumnIndex fun Cursor?.getInt(columnName: String) = this?.getIntOrNull(getColumnIndex(columnName)) fun Cursor?.getLong(columnName: String) = this?.getLongOrNull(getColumnIndex(columnName)) -fun OkHttpClient.Builder.installHttpsSupport(context: Context) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) { - try { - try { - ProviderInstaller.installIfNeeded(context) - } catch (e: Exception) { - Log.e("OkHttpTLSCompat", "Play Services not found or outdated") - - val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) - trustManagerFactory.init(null as KeyStore?) - - val x509TrustManager = trustManagerFactory.trustManagers.singleOrNull { it is X509TrustManager } as X509TrustManager? - ?: return - - val sc = SSLContext.getInstance("TLSv1.2") - sc.init(null, null, null) - sslSocketFactory(TLSSocketFactory(sc.socketFactory), x509TrustManager) - val cs: ConnectionSpec = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) - .tlsVersions(TlsVersion.TLS_1_0) - .tlsVersions(TlsVersion.TLS_1_1) - .tlsVersions(TlsVersion.TLS_1_2) - .build() - val specs: MutableList = ArrayList() - specs.add(cs) - specs.add(ConnectionSpec.COMPATIBLE_TLS) - specs.add(ConnectionSpec.CLEARTEXT) - connectionSpecs(specs) - } - } catch (exc: Exception) { - Log.e("OkHttpTLSCompat", "Error while setting TLS 1.2", exc) - } - } -} - fun CharSequence.containsAll(list: List, ignoreCase: Boolean = false): Boolean { for (i in list) { if (!contains(i, ignoreCase)) From a58a557fd0e810c9b648146a0051d3e2eff90459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 25 Mar 2021 11:18:40 +0100 Subject: [PATCH 024/113] [UI] Fix action switch/checkbox item padding. --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 363d5a21..447e4cc1 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -115,7 +115,7 @@ dependencies { implementation "eu.szkolny:agendacalendarview:1799f8ef47" implementation "eu.szkolny:cafebar:5bf0c618de" implementation "eu.szkolny.fslogin:lib:2.0.0" - implementation "eu.szkolny:material-about-library:0534abf316" + implementation "eu.szkolny:material-about-library:1d5ebaf47c" implementation "eu.szkolny:mhttp:af4b62e6e9" implementation "eu.szkolny:nachos:0e5dfcaceb" implementation "eu.szkolny.selective-dao:annotation:27f8f3f194" From 2933e214c6be4e35847c91f157e2dd54a0bf05b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 25 Mar 2021 11:37:40 +0100 Subject: [PATCH 025/113] [Layout] Migrate paddingStart/paddingEnd to paddingHorizontal. --- .../main/res/layout/attendance_config_dialog.xml | 3 +-- app/src/main/res/layout/dialog_config_grades.xml | 3 +-- app/src/main/res/layout/dialog_lesson_details.xml | 3 +-- app/src/main/res/layout/fragment_feedback.xml | 6 ++---- app/src/main/res/layout/grades_item_stats.xml | 6 ++---- .../res/layout/material_drawer_item_profile.xml | 5 +---- app/src/main/res/layout/md_simplelist_item.xml | 7 ++----- app/src/main/res/layout/timetable_lesson.xml | 12 ++++-------- app/src/main/res/layout/widget_lucky_number.xml | 13 +++---------- app/src/main/res/layout/widget_lucky_number_big.xml | 13 +++---------- .../main/res/layout/widget_lucky_number_dark.xml | 13 +++---------- .../res/layout/widget_lucky_number_dark_big.xml | 13 +++---------- 12 files changed, 26 insertions(+), 71 deletions(-) diff --git a/app/src/main/res/layout/attendance_config_dialog.xml b/app/src/main/res/layout/attendance_config_dialog.xml index 5d7db447..e691f762 100644 --- a/app/src/main/res/layout/attendance_config_dialog.xml +++ b/app/src/main/res/layout/attendance_config_dialog.xml @@ -13,8 +13,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:paddingStart="24dp" - android:paddingEnd="24dp"> + android:paddingHorizontal="24dp"> + android:paddingHorizontal="24dp"> + android:hint="" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/grades_item_stats.xml b/app/src/main/res/layout/grades_item_stats.xml index 1d990737..46e1a403 100644 --- a/app/src/main/res/layout/grades_item_stats.xml +++ b/app/src/main/res/layout/grades_item_stats.xml @@ -51,8 +51,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" - android:paddingStart="8dp" - android:paddingEnd="8dp"> + android:paddingHorizontal="8dp"> + android:paddingHorizontal="8dp"> + android:paddingHorizontal="@dimen/material_drawer_vertical_padding"> + android:paddingHorizontal="@dimen/md_dialog_frame_margin"> - \ No newline at end of file + diff --git a/app/src/main/res/layout/timetable_lesson.xml b/app/src/main/res/layout/timetable_lesson.xml index 9992da27..fc39e799 100644 --- a/app/src/main/res/layout/timetable_lesson.xml +++ b/app/src/main/res/layout/timetable_lesson.xml @@ -35,8 +35,7 @@ android:layout_height="wrap_content" android:background="@drawable/timetable_lesson_annotation" android:fontFamily="sans-serif-condensed" - android:paddingStart="8dp" - android:paddingEnd="8dp" + android:paddingHorizontal="8dp" android:text="@string/timetable_lesson_cancelled" android:textColor="#000" android:textSize="12sp" @@ -49,8 +48,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" - android:paddingStart="8dp" - android:paddingEnd="8dp" + android:paddingHorizontal="8dp" android:orientation="horizontal" android:baselineAligned="false"> @@ -109,8 +107,7 @@ android:fontFamily="sans-serif-condensed-light" android:includeFontPadding="false" android:layout_marginBottom="-4dp" - android:paddingStart="4dp" - android:paddingEnd="4dp" + android:paddingHorizontal="4dp" android:text="@{Integer.toString(lessonNumber)}" android:textSize="28sp" android:visibility="@{lessonNumber != null ? View.VISIBLE : View.GONE}" @@ -126,8 +123,7 @@ android:layout_weight="1" android:gravity="bottom" android:orientation="horizontal" - android:paddingStart="8dp" - android:paddingEnd="8dp"> + android:paddingHorizontal="8dp"> @@ -88,4 +81,4 @@ tools:visibility="gone" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/widget_lucky_number_big.xml b/app/src/main/res/layout/widget_lucky_number_big.xml index ca97f832..d1d8517b 100644 --- a/app/src/main/res/layout/widget_lucky_number_big.xml +++ b/app/src/main/res/layout/widget_lucky_number_big.xml @@ -1,5 +1,4 @@ @@ -86,4 +79,4 @@ tools:visibility="gone" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/widget_lucky_number_dark.xml b/app/src/main/res/layout/widget_lucky_number_dark.xml index 90ca469d..93f97e2d 100644 --- a/app/src/main/res/layout/widget_lucky_number_dark.xml +++ b/app/src/main/res/layout/widget_lucky_number_dark.xml @@ -1,5 +1,4 @@ @@ -85,4 +78,4 @@ tools:visibility="gone" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/widget_lucky_number_dark_big.xml b/app/src/main/res/layout/widget_lucky_number_dark_big.xml index 58684cbe..950c7064 100644 --- a/app/src/main/res/layout/widget_lucky_number_dark_big.xml +++ b/app/src/main/res/layout/widget_lucky_number_dark_big.xml @@ -1,5 +1,4 @@ @@ -86,4 +79,4 @@ tools:visibility="gone" /> - \ No newline at end of file + From 1364691a462a711fc2ce9c89f24bbae1dc6676c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 25 Mar 2021 11:49:22 +0100 Subject: [PATCH 026/113] [Layout] Migrate paddingLeft/paddingRight to paddingHorizontal. --- app/src/main/res/layout/activity_crash.xml | 5 ++-- .../res/layout/attendance_details_dialog.xml | 5 ++-- app/src/main/res/layout/dialog_changelog.xml | 5 ++-- app/src/main/res/layout/dialog_day.xml | 5 ++-- .../main/res/layout/dialog_event_details.xml | 5 ++-- app/src/main/res/layout/dialog_event_list.xml | 3 +-- .../main/res/layout/dialog_grade_details.xml | 5 ++-- .../res/layout/dialog_lesson_change_list.xml | 5 ++-- .../main/res/layout/dialog_lesson_details.xml | 5 ++-- .../layout/dialog_register_unavailable.xml | 3 +-- .../layout/dialog_teacher_absence_list.xml | 5 ++-- app/src/main/res/layout/dialog_template.xml | 7 +++--- .../res/layout/fragment_grades_editor.xml | 14 ++++------- .../res/layout/material_drawer_header.xml | 12 ++++------ .../layout/material_drawer_item_profile.xml | 3 +-- app/src/main/res/layout/message_fragment.xml | 21 ++++++----------- app/src/main/res/layout/messages_details.xml | 23 +++++++------------ app/src/main/res/layout/recaptcha_view.xml | 3 +-- app/src/main/res/layout/row_homework_item.xml | 3 +-- app/src/main/res/layout/row_notices_item.xml | 5 ++-- .../main/res/layout/widget_notifications.xml | 5 ++-- .../res/layout/widget_notifications_big.xml | 5 ++-- .../res/layout/widget_notifications_dark.xml | 5 ++-- .../layout/widget_notifications_dark_big.xml | 5 ++-- app/src/main/res/layout/widget_timetable.xml | 8 +++---- .../main/res/layout/widget_timetable_big.xml | 8 +++---- .../main/res/layout/widget_timetable_dark.xml | 6 ++--- .../res/layout/widget_timetable_dark_big.xml | 8 +++---- 28 files changed, 71 insertions(+), 121 deletions(-) diff --git a/app/src/main/res/layout/activity_crash.xml b/app/src/main/res/layout/activity_crash.xml index 459e4751..283865e5 100644 --- a/app/src/main/res/layout/activity_crash.xml +++ b/app/src/main/res/layout/activity_crash.xml @@ -20,8 +20,7 @@ android:gravity="center" android:orientation="vertical" android:paddingBottom="@dimen/customactivityoncrash_activity_vertical_margin" - android:paddingLeft="@dimen/customactivityoncrash_activity_horizontal_margin" - android:paddingRight="@dimen/customactivityoncrash_activity_horizontal_margin" + android:paddingHorizontal="@dimen/customactivityoncrash_activity_horizontal_margin" android:paddingTop="@dimen/customactivityoncrash_activity_vertical_margin"> - \ No newline at end of file + diff --git a/app/src/main/res/layout/attendance_details_dialog.xml b/app/src/main/res/layout/attendance_details_dialog.xml index 59ec37c3..34a2dc0d 100644 --- a/app/src/main/res/layout/attendance_details_dialog.xml +++ b/app/src/main/res/layout/attendance_details_dialog.xml @@ -27,9 +27,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:paddingLeft="24dp" - android:paddingTop="24dp" - android:paddingRight="24dp"> + android:paddingHorizontal="24dp" + android:paddingTop="24dp"> - \ No newline at end of file + diff --git a/app/src/main/res/layout/dialog_day.xml b/app/src/main/res/layout/dialog_day.xml index 484f2b2c..14030480 100644 --- a/app/src/main/res/layout/dialog_day.xml +++ b/app/src/main/res/layout/dialog_day.xml @@ -16,9 +16,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:paddingLeft="16dp" - android:paddingTop="24dp" - android:paddingRight="16dp"> + android:paddingHorizontal="16dp" + android:paddingTop="24dp"> + android:paddingHorizontal="24dp" + android:paddingTop="24dp"> diff --git a/app/src/main/res/layout/dialog_grade_details.xml b/app/src/main/res/layout/dialog_grade_details.xml index 92781772..b53ff721 100644 --- a/app/src/main/res/layout/dialog_grade_details.xml +++ b/app/src/main/res/layout/dialog_grade_details.xml @@ -41,9 +41,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:paddingLeft="24dp" - android:paddingTop="24dp" - android:paddingRight="24dp"> + android:paddingHorizontal="24dp" + android:paddingTop="24dp"> diff --git a/app/src/main/res/layout/dialog_lesson_details.xml b/app/src/main/res/layout/dialog_lesson_details.xml index 8b0154c1..d1dba0b1 100644 --- a/app/src/main/res/layout/dialog_lesson_details.xml +++ b/app/src/main/res/layout/dialog_lesson_details.xml @@ -31,9 +31,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:paddingLeft="16dp" - android:paddingTop="24dp" - android:paddingRight="16dp"> + android:paddingHorizontal="16dp" + android:paddingTop="24dp"> diff --git a/app/src/main/res/layout/dialog_template.xml b/app/src/main/res/layout/dialog_template.xml index e9b1011f..2aa3790d 100644 --- a/app/src/main/res/layout/dialog_template.xml +++ b/app/src/main/res/layout/dialog_template.xml @@ -8,9 +8,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:paddingLeft="16dp" - android:paddingTop="24dp" - android:paddingRight="16dp"> + android:paddingHorizontal="16dp" + android:paddingTop="24dp"> - \ No newline at end of file + diff --git a/app/src/main/res/layout/fragment_grades_editor.xml b/app/src/main/res/layout/fragment_grades_editor.xml index 805aee24..df49ef4d 100644 --- a/app/src/main/res/layout/fragment_grades_editor.xml +++ b/app/src/main/res/layout/fragment_grades_editor.xml @@ -47,8 +47,7 @@ android:layout_marginEnd="5dp" android:layout_marginRight="5dp" android:background="@drawable/bg_rounded_4dp" - android:paddingLeft="5dp" - android:paddingRight="5dp" + android:paddingHorizontal="5dp" android:textColor="@color/black" android:textStyle="bold" tools:text="0.63" /> @@ -74,8 +73,7 @@ android:layout_marginEnd="5dp" android:layout_marginRight="5dp" android:background="@drawable/bg_rounded_4dp" - android:paddingLeft="5dp" - android:paddingRight="5dp" + android:paddingHorizontal="5dp" android:textColor="@color/black" android:textStyle="bold" tools:text="2.75" /> @@ -107,8 +105,7 @@ android:layout_marginEnd="5dp" android:layout_marginRight="5dp" android:background="@drawable/bg_rounded_4dp" - android:paddingLeft="5dp" - android:paddingRight="5dp" + android:paddingHorizontal="5dp" android:textColor="@color/black" android:textStyle="bold" tools:text="0.63" /> @@ -134,8 +131,7 @@ android:layout_marginEnd="5dp" android:layout_marginRight="5dp" android:background="@drawable/bg_rounded_4dp" - android:paddingLeft="5dp" - android:paddingRight="5dp" + android:paddingHorizontal="5dp" android:textColor="@color/black" android:textStyle="bold" tools:text="2.75" /> @@ -179,4 +175,4 @@ android:layout_height="match_parent" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/material_drawer_header.xml b/app/src/main/res/layout/material_drawer_header.xml index b286b60c..51fffb92 100644 --- a/app/src/main/res/layout/material_drawer_header.xml +++ b/app/src/main/res/layout/material_drawer_header.xml @@ -48,8 +48,7 @@ android:gravity="center" android:lines="1" android:minWidth="20dp" - android:paddingLeft="1dp" - android:paddingRight="1dp" + android:paddingHorizontal="1dp" android:singleLine="true" android:textSize="@dimen/material_drawer_item_badge_text" app:layout_constraintBottom_toBottomOf="@id/material_drawer_account_header_current" @@ -82,8 +81,7 @@ android:gravity="center" android:lines="1" android:minWidth="20dp" - android:paddingLeft="1dp" - android:paddingRight="1dp" + android:paddingHorizontal="1dp" android:singleLine="true" android:textSize="@dimen/material_drawer_item_badge_small_text" app:layout_constraintBottom_toBottomOf="@id/material_drawer_account_header_small_first" @@ -116,8 +114,7 @@ android:gravity="center" android:lines="1" android:minWidth="20dp" - android:paddingLeft="1dp" - android:paddingRight="1dp" + android:paddingHorizontal="1dp" android:singleLine="true" android:textSize="@dimen/material_drawer_item_badge_small_text" app:layout_constraintBottom_toBottomOf="@id/material_drawer_account_header_small_second" @@ -150,8 +147,7 @@ android:gravity="center" android:lines="1" android:minWidth="20dp" - android:paddingLeft="1dp" - android:paddingRight="1dp" + android:paddingHorizontal="1dp" android:singleLine="true" android:textSize="@dimen/material_drawer_item_badge_small_text" app:layout_constraintBottom_toBottomOf="@id/material_drawer_account_header_small_third" diff --git a/app/src/main/res/layout/material_drawer_item_profile.xml b/app/src/main/res/layout/material_drawer_item_profile.xml index 89643465..a71ce017 100644 --- a/app/src/main/res/layout/material_drawer_item_profile.xml +++ b/app/src/main/res/layout/material_drawer_item_profile.xml @@ -95,8 +95,7 @@ android:gravity="center" android:lines="1" android:minWidth="20dp" - android:paddingLeft="1dp" - android:paddingRight="1dp" + android:paddingHorizontal="1dp" android:singleLine="true" android:textSize="@dimen/material_drawer_item_primary_text" tools:text="99" /> diff --git a/app/src/main/res/layout/message_fragment.xml b/app/src/main/res/layout/message_fragment.xml index bb252b11..4179c21f 100644 --- a/app/src/main/res/layout/message_fragment.xml +++ b/app/src/main/res/layout/message_fragment.xml @@ -117,9 +117,8 @@ android:background="?selectableItemBackground" android:ellipsize="end" android:maxLines="2" - android:paddingLeft="8dp" + android:paddingHorizontal="8dp" android:paddingTop="12dp" - android:paddingRight="8dp" android:textAppearance="@style/NavView.TextView.Subtitle" tools:text="Allegro - wysyłamy duużo wiadomości!!! Masz nowe oferty! Możesz kupić nowego laptopa! Ale super! Ehh, to jest nadawca a nie temat więc nwm czemu to tutaj wpisałem" /> @@ -142,8 +141,7 @@ android:layout_marginTop="8dp" android:layout_marginBottom="8dp" android:minHeight="250dp" - android:paddingLeft="16dp" - android:paddingRight="16dp" + android:paddingHorizontal="16dp" android:textIsSelectable="true" tools:text="To jest treść wiadomości.\n\nZazwyczaj ma wiele linijek.\n\nTak" /> @@ -165,8 +163,7 @@ android:id="@+id/recipients" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingLeft="16dp" - android:paddingRight="16dp" + android:paddingHorizontal="16dp" tools:text=" - Jan Kowalski, przeczytano: nie\n - Adam Dodatkowy, przeczytano: 20 marca, 17:35" /> @@ -306,9 +300,8 @@ android:background="@drawable/bg_rounded_ripple" android:gravity="center" android:orientation="vertical" - android:paddingLeft="4dp" + android:paddingHorizontal="4dp" android:paddingTop="8dp" - android:paddingRight="4dp" android:paddingBottom="8dp" android:visibility="visible"> diff --git a/app/src/main/res/layout/messages_details.xml b/app/src/main/res/layout/messages_details.xml index 3be6310b..acb4d769 100644 --- a/app/src/main/res/layout/messages_details.xml +++ b/app/src/main/res/layout/messages_details.xml @@ -132,9 +132,8 @@ android:background="?selectableItemBackground" android:ellipsize="end" android:maxLines="3" - android:paddingLeft="8dp" + android:paddingHorizontal="8dp" android:paddingTop="12dp" - android:paddingRight="8dp" android:textAppearance="@style/NavView.TextView.Subtitle" app:layout_constraintEnd_toStartOf="@+id/messageDate" app:layout_constraintStart_toEndOf="@+id/messageProfileBackground" @@ -163,8 +162,7 @@ android:layout_marginBottom="8dp" android:autoLink="all" android:minHeight="250dp" - android:paddingLeft="16dp" - android:paddingRight="16dp" + android:paddingHorizontal="16dp" android:textIsSelectable="true" tools:text="To jest treść wiadomości.\n\nZazwyczaj ma wiele linijek.\n\nTak" /> @@ -186,8 +184,7 @@ android:id="@+id/messageRecipients" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingLeft="16dp" - android:paddingRight="16dp" + android:paddingHorizontal="16dp" tools:text=" - Jan Kowalski, przeczytano: nie\n - Adam Dodatkowy, przeczytano: 20 marca, 17:35" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/recaptcha_view.xml b/app/src/main/res/layout/recaptcha_view.xml index dba7824b..7e362e0c 100644 --- a/app/src/main/res/layout/recaptcha_view.xml +++ b/app/src/main/res/layout/recaptcha_view.xml @@ -8,9 +8,8 @@ - \ No newline at end of file + diff --git a/app/src/main/res/layout/widget_notifications.xml b/app/src/main/res/layout/widget_notifications.xml index 5b652da0..20b0f490 100644 --- a/app/src/main/res/layout/widget_notifications.xml +++ b/app/src/main/res/layout/widget_notifications.xml @@ -25,8 +25,7 @@ android:layout_height="wrap_content" android:gravity="center_vertical" android:maxLines="1" - android:paddingLeft="15.0dip" - android:paddingRight="15.0dip" + android:paddingHorizontal="15dp" android:textColor="@color/primaryTextDark" android:textSize="18.0sp" android:ellipsize="end" @@ -67,4 +66,4 @@ - \ No newline at end of file + diff --git a/app/src/main/res/layout/widget_notifications_big.xml b/app/src/main/res/layout/widget_notifications_big.xml index f5695da2..e97b8e48 100644 --- a/app/src/main/res/layout/widget_notifications_big.xml +++ b/app/src/main/res/layout/widget_notifications_big.xml @@ -26,8 +26,7 @@ android:ellipsize="end" android:gravity="center_vertical" android:maxLines="1" - android:paddingLeft="15.0dip" - android:paddingRight="15.0dip" + android:paddingHorizontal="15dp" android:text="@string/widget_notifications_title" android:textColor="@color/primaryTextDark" android:textSize="24sp" /> @@ -68,4 +67,4 @@ - \ No newline at end of file + diff --git a/app/src/main/res/layout/widget_notifications_dark.xml b/app/src/main/res/layout/widget_notifications_dark.xml index 19a639ff..cf960ece 100644 --- a/app/src/main/res/layout/widget_notifications_dark.xml +++ b/app/src/main/res/layout/widget_notifications_dark.xml @@ -25,8 +25,7 @@ android:layout_height="wrap_content" android:gravity="center_vertical" android:maxLines="1" - android:paddingLeft="15.0dip" - android:paddingRight="15.0dip" + android:paddingHorizontal="15dp" android:textColor="@color/primaryTextDark" android:textSize="18.0sp" android:ellipsize="end" @@ -67,4 +66,4 @@ - \ No newline at end of file + diff --git a/app/src/main/res/layout/widget_notifications_dark_big.xml b/app/src/main/res/layout/widget_notifications_dark_big.xml index 47af8347..64aaabcf 100644 --- a/app/src/main/res/layout/widget_notifications_dark_big.xml +++ b/app/src/main/res/layout/widget_notifications_dark_big.xml @@ -26,8 +26,7 @@ android:ellipsize="end" android:gravity="center_vertical" android:maxLines="1" - android:paddingLeft="15.0dip" - android:paddingRight="15.0dip" + android:paddingHorizontal="15dp" android:text="@string/widget_notifications_title" android:textColor="@color/primaryTextDark" android:textSize="24sp" /> @@ -68,4 +67,4 @@ - \ No newline at end of file + diff --git a/app/src/main/res/layout/widget_timetable.xml b/app/src/main/res/layout/widget_timetable.xml index 792a4f0d..4f990ef8 100644 --- a/app/src/main/res/layout/widget_timetable.xml +++ b/app/src/main/res/layout/widget_timetable.xml @@ -26,8 +26,7 @@ android:layout_height="wrap_content" android:gravity="center_vertical" android:maxLines="1" - android:paddingLeft="15.0dip" - android:paddingRight="15.0dip" + android:paddingHorizontal="15dp" android:textColor="@color/primaryTextDark" android:textSize="18.0sp" android:ellipsize="end" @@ -39,8 +38,7 @@ android:layout_height="wrap_content" android:gravity="center_vertical" android:maxLines="1" - android:paddingLeft="15.0dip" - android:paddingRight="15.0dip" + android:paddingHorizontal="15dp" android:textColor="@color/primaryTextDark" android:textSize="10.0sp" tools:text="Test test etst tetete" /> @@ -115,4 +113,4 @@ - \ No newline at end of file + diff --git a/app/src/main/res/layout/widget_timetable_big.xml b/app/src/main/res/layout/widget_timetable_big.xml index 1b82f9b1..264316a3 100644 --- a/app/src/main/res/layout/widget_timetable_big.xml +++ b/app/src/main/res/layout/widget_timetable_big.xml @@ -27,8 +27,7 @@ android:ellipsize="end" android:gravity="center_vertical" android:maxLines="1" - android:paddingLeft="15.0dip" - android:paddingRight="15.0dip" + android:paddingHorizontal="15dp" android:text="@string/widget_timetable_title" android:textColor="@color/primaryTextDark" android:textSize="24sp" /> @@ -39,8 +38,7 @@ android:layout_height="wrap_content" android:gravity="center_vertical" android:maxLines="1" - android:paddingLeft="15.0dip" - android:paddingRight="15.0dip" + android:paddingHorizontal="15dp" android:textColor="@color/primaryTextDark" android:textSize="16sp" tools:text="Test test etst tetete" /> @@ -116,4 +114,4 @@ - \ No newline at end of file + diff --git a/app/src/main/res/layout/widget_timetable_dark.xml b/app/src/main/res/layout/widget_timetable_dark.xml index 87034cd5..72301f70 100644 --- a/app/src/main/res/layout/widget_timetable_dark.xml +++ b/app/src/main/res/layout/widget_timetable_dark.xml @@ -26,8 +26,7 @@ android:layout_height="wrap_content" android:gravity="center_vertical" android:maxLines="1" - android:paddingLeft="15.0dip" - android:paddingRight="15.0dip" + android:paddingHorizontal="15dp" android:textColor="@color/primaryTextDark" android:textSize="18.0sp" android:ellipsize="end" @@ -39,8 +38,7 @@ android:layout_height="wrap_content" android:gravity="center_vertical" android:maxLines="1" - android:paddingLeft="15.0dip" - android:paddingRight="15.0dip" + android:paddingHorizontal="15dp" android:textColor="@color/primaryTextDark" android:textSize="10.0sp" tools:text="Test test etst tetete" /> diff --git a/app/src/main/res/layout/widget_timetable_dark_big.xml b/app/src/main/res/layout/widget_timetable_dark_big.xml index cbc28535..cba3e565 100644 --- a/app/src/main/res/layout/widget_timetable_dark_big.xml +++ b/app/src/main/res/layout/widget_timetable_dark_big.xml @@ -27,8 +27,7 @@ android:ellipsize="end" android:gravity="center_vertical" android:maxLines="1" - android:paddingLeft="15.0dip" - android:paddingRight="15.0dip" + android:paddingHorizontal="15dp" android:text="@string/widget_timetable_title" android:textColor="@color/primaryTextDark" android:textSize="24sp" /> @@ -39,8 +38,7 @@ android:layout_height="wrap_content" android:gravity="center_vertical" android:maxLines="1" - android:paddingLeft="15.0dip" - android:paddingRight="15.0dip" + android:paddingHorizontal="15dp" android:textColor="@color/primaryTextDark" android:textSize="16sp" tools:text="Test test etst tetete" /> @@ -116,4 +114,4 @@ - \ No newline at end of file + From 9ef37c46efd24f825f802a72ec3640fd7b6dbb1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 25 Mar 2021 11:54:52 +0100 Subject: [PATCH 027/113] [Layout] Migrate paddingTop/paddingBottom to paddingVertical. --- app/src/main/res/layout/attendance_config_dialog.xml | 2 +- app/src/main/res/layout/dialog_day.xml | 3 +-- app/src/main/res/layout/dialog_event_list.xml | 3 +-- app/src/main/res/layout/dialog_event_manual_v2.xml | 3 +-- .../main/res/layout/dialog_lesson_change_list.xml | 3 +-- app/src/main/res/layout/dialog_lesson_details.xml | 3 +-- .../main/res/layout/dialog_register_unavailable.xml | 3 +-- .../main/res/layout/dialog_teacher_absence_list.xml | 3 +-- app/src/main/res/layout/grades_item_grade.xml | 3 +-- app/src/main/res/layout/login_summary_fragment.xml | 3 +-- app/src/main/res/layout/message_fragment.xml | 12 ++++-------- app/src/main/res/layout/messages_details.xml | 9 +++------ app/src/main/res/layout/messages_item.xml | 5 ++--- app/src/main/res/layout/messages_list_item.xml | 3 +-- app/src/main/res/layout/row_attendance_item.xml | 3 +-- app/src/main/res/layout/row_grades_editor_item.xml | 3 +-- 16 files changed, 22 insertions(+), 42 deletions(-) diff --git a/app/src/main/res/layout/attendance_config_dialog.xml b/app/src/main/res/layout/attendance_config_dialog.xml index e691f762..a75da4ac 100644 --- a/app/src/main/res/layout/attendance_config_dialog.xml +++ b/app/src/main/res/layout/attendance_config_dialog.xml @@ -33,7 +33,7 @@ diff --git a/app/src/main/res/layout/dialog_event_list.xml b/app/src/main/res/layout/dialog_event_list.xml index 93020786..d321844b 100644 --- a/app/src/main/res/layout/dialog_event_list.xml +++ b/app/src/main/res/layout/dialog_event_list.xml @@ -88,8 +88,7 @@ android:layout_marginTop="8dp" android:clipToPadding="false" android:paddingHorizontal="16dp" - android:paddingTop="8dp" - android:paddingBottom="8dp" + android:paddingVertical="8dp" tools:listitem="@layout/row_dialog_event_list_item" /> diff --git a/app/src/main/res/layout/dialog_event_manual_v2.xml b/app/src/main/res/layout/dialog_event_manual_v2.xml index 0c091883..b8e12927 100644 --- a/app/src/main/res/layout/dialog_event_manual_v2.xml +++ b/app/src/main/res/layout/dialog_event_manual_v2.xml @@ -139,8 +139,7 @@ android:id="@+id/showMore" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingTop="16dp" - android:paddingBottom="16dp" + android:paddingVertical="16dp" android:text="@string/dialog_event_manual_more_options" android:background="?selectableItemBackground" diff --git a/app/src/main/res/layout/dialog_lesson_change_list.xml b/app/src/main/res/layout/dialog_lesson_change_list.xml index 47c109f4..2925813f 100644 --- a/app/src/main/res/layout/dialog_lesson_change_list.xml +++ b/app/src/main/res/layout/dialog_lesson_change_list.xml @@ -8,7 +8,6 @@ android:layout_height="match_parent" android:clipToPadding="false" android:paddingHorizontal="24dp" - android:paddingTop="8dp" - android:paddingBottom="8dp" + android:paddingVertical="8dp" tools:listitem="@layout/timetable_lesson" /> diff --git a/app/src/main/res/layout/dialog_lesson_details.xml b/app/src/main/res/layout/dialog_lesson_details.xml index d1dba0b1..3c891d4d 100644 --- a/app/src/main/res/layout/dialog_lesson_details.xml +++ b/app/src/main/res/layout/dialog_lesson_details.xml @@ -304,8 +304,7 @@ android:layout_height="wrap_content" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" - android:paddingTop="16dp" - android:paddingBottom="16dp" + android:paddingVertical="16dp" android:orientation="vertical" android:visibility="gone" tools:visibility="visible"> diff --git a/app/src/main/res/layout/dialog_register_unavailable.xml b/app/src/main/res/layout/dialog_register_unavailable.xml index 056fcba7..0880179d 100644 --- a/app/src/main/res/layout/dialog_register_unavailable.xml +++ b/app/src/main/res/layout/dialog_register_unavailable.xml @@ -37,8 +37,7 @@ android:layout_height="wrap_content" android:orientation="vertical" android:paddingHorizontal="24dp" - android:paddingTop="16dp" - android:paddingBottom="16dp"> + android:paddingVertical="16dp"> diff --git a/app/src/main/res/layout/grades_item_grade.xml b/app/src/main/res/layout/grades_item_grade.xml index 10cc06b2..d7fe38e3 100644 --- a/app/src/main/res/layout/grades_item_grade.xml +++ b/app/src/main/res/layout/grades_item_grade.xml @@ -11,8 +11,7 @@ android:layout_height="wrap_content" android:background="?selectableItemBackground" android:orientation="horizontal" - android:paddingTop="8dp" - android:paddingBottom="8dp"> + android:paddingVertical="8dp"> + android:paddingVertical="8dp"> + android:paddingVertical="8dp"> + android:paddingVertical="8dp"> + android:paddingVertical="8dp"> + android:paddingVertical="8dp"> - \ No newline at end of file + diff --git a/app/src/main/res/layout/messages_list_item.xml b/app/src/main/res/layout/messages_list_item.xml index 6bd8af55..686e9dce 100644 --- a/app/src/main/res/layout/messages_list_item.xml +++ b/app/src/main/res/layout/messages_list_item.xml @@ -105,8 +105,7 @@ android:layout_marginEnd="4dp" android:layout_marginRight="4dp" android:adjustViewBounds="true" - android:paddingTop="2dp" - android:paddingBottom="2dp" + android:paddingVertical="2dp" android:scaleType="fitCenter" app:iiv_color="?android:textColorSecondary" app:iiv_icon="cmd-attachment" diff --git a/app/src/main/res/layout/row_attendance_item.xml b/app/src/main/res/layout/row_attendance_item.xml index 5631ab87..d6e6bfd2 100644 --- a/app/src/main/res/layout/row_attendance_item.xml +++ b/app/src/main/res/layout/row_attendance_item.xml @@ -4,8 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingTop="8dp" - android:paddingBottom="8dp"> + android:paddingVertical="8dp"> + android:paddingVertical="8dp"> Date: Thu, 25 Mar 2021 12:28:33 +0100 Subject: [PATCH 028/113] [Layout] Migrate marginStart/marginEnd to marginHorizontal. --- app/src/main/res/layout/activity_gtfo.xml | 13 +++------- app/src/main/res/layout/card_update.xml | 7 ++---- .../res/layout/fragment_announcements.xml | 9 ++----- .../main/res/layout/fragment_attendance.xml | 3 +-- .../main/res/layout/fragment_behaviour.xml | 5 ++-- app/src/main/res/layout/fragment_debug.xml | 25 ++++--------------- app/src/main/res/layout/fragment_feedback.xml | 15 +++-------- .../main/res/layout/fragment_timetable_v2.xml | 6 ++--- app/src/main/res/layout/grades_item_grade.xml | 5 +--- app/src/main/res/layout/grades_item_stats.xml | 6 ++--- .../res/layout/messages_compose_fragment.xml | 6 ++--- app/src/main/res/layout/messages_details.xml | 7 +----- app/src/main/res/layout/messages_item.xml | 10 ++------ .../main/res/layout/messages_list_item.xml | 10 ++------ .../main/res/layout/row_attendance_item.xml | 10 ++------ .../res/layout/row_dialog_event_list_item.xml | 10 ++------ .../row_dialog_teacher_absence_item.xml | 3 +-- app/src/main/res/layout/row_homework_item.xml | 3 +-- .../main/res/layout/row_timetable_item.xml | 15 +++-------- .../main/res/layout/timetable_free_day.xml | 5 ++-- app/src/main/res/layout/timetable_lesson.xml | 5 +--- .../res/layout/timetable_no_timetable.xml | 5 ++-- 22 files changed, 45 insertions(+), 138 deletions(-) diff --git a/app/src/main/res/layout/activity_gtfo.xml b/app/src/main/res/layout/activity_gtfo.xml index f0ff621c..668549e6 100644 --- a/app/src/main/res/layout/activity_gtfo.xml +++ b/app/src/main/res/layout/activity_gtfo.xml @@ -1,24 +1,17 @@ - - \ No newline at end of file + diff --git a/app/src/main/res/layout/card_update.xml b/app/src/main/res/layout/card_update.xml index 5218e51c..3f937409 100644 --- a/app/src/main/res/layout/card_update.xml +++ b/app/src/main/res/layout/card_update.xml @@ -53,10 +53,7 @@ android:id="@+id/cardUpdateText" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginLeft="8dp" - android:layout_marginEnd="8dp" - android:layout_marginRight="8dp" + android:layout_marginHorizontal="8dp" android:layout_marginBottom="8dp" android:text="@string/card_update_text_format" android:textAppearance="@style/TextAppearance.AppCompat.Small" @@ -86,4 +83,4 @@ - \ No newline at end of file + diff --git a/app/src/main/res/layout/fragment_announcements.xml b/app/src/main/res/layout/fragment_announcements.xml index e25911f8..cb7d38d0 100644 --- a/app/src/main/res/layout/fragment_announcements.xml +++ b/app/src/main/res/layout/fragment_announcements.xml @@ -21,12 +21,7 @@ android:id="@+id/announcementsNoData" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginLeft="8dp" - android:layout_marginTop="8dp" - android:layout_marginEnd="8dp" - android:layout_marginRight="8dp" - android:layout_marginBottom="8dp" + android:layout_margin="8dp" android:text="@string/school_notices_no_data" android:textSize="18sp" android:textStyle="italic" @@ -37,4 +32,4 @@ app:layout_constraintTop_toTopOf="parent" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/fragment_attendance.xml b/app/src/main/res/layout/fragment_attendance.xml index c0ddb3d4..da464f3b 100644 --- a/app/src/main/res/layout/fragment_attendance.xml +++ b/app/src/main/res/layout/fragment_attendance.xml @@ -152,8 +152,7 @@ android:id="@+id/attendancePercentage" android:layout_width="160dp" android:layout_height="160dp" - android:layout_marginStart="8dp" - android:layout_marginEnd="8dp" + android:layout_marginHorizontal="8dp" android:layout_weight="1" app:direction="clockwise" app:drawDot="false" diff --git a/app/src/main/res/layout/fragment_behaviour.xml b/app/src/main/res/layout/fragment_behaviour.xml index 23d2a99f..ddd9faed 100644 --- a/app/src/main/res/layout/fragment_behaviour.xml +++ b/app/src/main/res/layout/fragment_behaviour.xml @@ -17,8 +17,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" - android:layout_marginStart="8dp" - android:layout_marginEnd="8dp"> + android:layout_marginHorizontal="8dp"> - \ No newline at end of file + diff --git a/app/src/main/res/layout/fragment_debug.xml b/app/src/main/res/layout/fragment_debug.xml index 2fecffa5..bf27e110 100644 --- a/app/src/main/res/layout/fragment_debug.xml +++ b/app/src/main/res/layout/fragment_debug.xml @@ -11,11 +11,8 @@ android:id="@+id/runLayout" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginLeft="8dp" + android:layout_marginHorizontal="8dp" android:layout_marginTop="8dp" - android:layout_marginEnd="8dp" - android:layout_marginRight="8dp" style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -33,10 +30,7 @@ android:id="@+id/textView3" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginLeft="8dp" - android:layout_marginEnd="8dp" - android:layout_marginRight="8dp" + android:layout_marginHorizontal="8dp" android:text="@string/debug_notice" android:textSize="18sp" app:layout_constraintEnd_toEndOf="parent" @@ -48,10 +42,7 @@ android:id="@+id/debugRegister" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginLeft="8dp" - android:layout_marginEnd="8dp" - android:layout_marginRight="8dp" + android:layout_marginHorizontal="8dp" style="@style/Widget.MaterialComponents.Button" android:text="Run" app:layout_constraintEnd_toStartOf="@+id/guideline2" @@ -69,10 +60,7 @@ android:id="@+id/debugAppconfig" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginLeft="8dp" - android:layout_marginEnd="8dp" - android:layout_marginRight="8dp" + android:layout_marginHorizontal="8dp" style="@style/Widget.MaterialComponents.Button" android:text="AppConfig" app:layout_constraintEnd_toStartOf="@+id/guideline3" @@ -90,10 +78,7 @@ android:id="@+id/debugAppprofile" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginLeft="8dp" - android:layout_marginEnd="8dp" - android:layout_marginRight="8dp" + android:layout_marginHorizontal="8dp" style="@style/Widget.MaterialComponents.Button" android:text="AppProfile" app:layout_constraintEnd_toEndOf="parent" diff --git a/app/src/main/res/layout/fragment_feedback.xml b/app/src/main/res/layout/fragment_feedback.xml index 57918bb8..64aa6a4f 100644 --- a/app/src/main/res/layout/fragment_feedback.xml +++ b/app/src/main/res/layout/fragment_feedback.xml @@ -30,11 +30,8 @@ android:id="@+id/faqText" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginLeft="8dp" + android:layout_marginHorizontal="8dp" android:layout_marginTop="8dp" - android:layout_marginEnd="8dp" - android:layout_marginRight="8dp" android:autoLink="all" android:background="?selectableItemBackground" android:text="@string/feedback_faq" @@ -64,11 +61,8 @@ @@ -76,11 +70,8 @@ style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginLeft="8dp" + android:layout_marginHorizontal="8dp" android:layout_marginTop="8dp" - android:layout_marginEnd="8dp" - android:layout_marginRight="8dp" android:hint="@string/feedback_ask_a_question" app:errorEnabled="true" app:hintAnimationEnabled="true" diff --git a/app/src/main/res/layout/fragment_timetable_v2.xml b/app/src/main/res/layout/fragment_timetable_v2.xml index 953638cf..af7995d2 100644 --- a/app/src/main/res/layout/fragment_timetable_v2.xml +++ b/app/src/main/res/layout/fragment_timetable_v2.xml @@ -73,9 +73,8 @@ @@ -83,9 +82,8 @@ diff --git a/app/src/main/res/layout/grades_item_grade.xml b/app/src/main/res/layout/grades_item_grade.xml index d7fe38e3..1ff1f0b0 100644 --- a/app/src/main/res/layout/grades_item_grade.xml +++ b/app/src/main/res/layout/grades_item_grade.xml @@ -88,10 +88,7 @@ android:id="@+id/gradeCategory" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginLeft="8dp" - android:layout_marginEnd="8dp" - android:layout_marginRight="8dp" + android:layout_marginHorizontal="8dp" android:ellipsize="end" android:maxWidth="200dp" android:maxLines="1" diff --git a/app/src/main/res/layout/grades_item_stats.xml b/app/src/main/res/layout/grades_item_stats.xml index 46e1a403..765aed8b 100644 --- a/app/src/main/res/layout/grades_item_stats.xml +++ b/app/src/main/res/layout/grades_item_stats.xml @@ -41,8 +41,7 @@ android:id="@+id/normalTitle" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginEnd="8dp" + android:layout_marginHorizontal="8dp" android:text="@string/grades_stats_normal" android:textAppearance="@style/NavView.TextView.Subtitle" /> @@ -182,9 +181,8 @@ android:id="@+id/pointTitle" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginStart="8dp" + android:layout_marginHorizontal="8dp" android:layout_marginTop="8dp" - android:layout_marginEnd="8dp" android:text="@string/grades_stats_point" android:textAppearance="@style/NavView.TextView.Subtitle" /> diff --git a/app/src/main/res/layout/messages_compose_fragment.xml b/app/src/main/res/layout/messages_compose_fragment.xml index fa056966..9363a92f 100644 --- a/app/src/main/res/layout/messages_compose_fragment.xml +++ b/app/src/main/res/layout/messages_compose_fragment.xml @@ -87,8 +87,7 @@ android:id="@+id/fontStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginEnd="8dp" + android:layout_marginHorizontal="8dp" android:layout_marginTop="4dp"> diff --git a/app/src/main/res/layout/messages_details.xml b/app/src/main/res/layout/messages_details.xml index cddc8a89..5146b956 100644 --- a/app/src/main/res/layout/messages_details.xml +++ b/app/src/main/res/layout/messages_details.xml @@ -59,12 +59,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" - android:layout_marginStart="8dp" - android:layout_marginLeft="8dp" - android:layout_marginTop="8dp" - android:layout_marginEnd="8dp" - android:layout_marginRight="8dp" - android:layout_marginBottom="8dp" + android:layout_margin="8dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" diff --git a/app/src/main/res/layout/messages_item.xml b/app/src/main/res/layout/messages_item.xml index f1921e45..d095a992 100644 --- a/app/src/main/res/layout/messages_item.xml +++ b/app/src/main/res/layout/messages_item.xml @@ -63,10 +63,7 @@ android:id="@+id/messageSubject" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginLeft="8dp" - android:layout_marginEnd="8dp" - android:layout_marginRight="8dp" + android:layout_marginHorizontal="8dp" android:singleLine="true" android:textStyle="bold" app:layout_constraintEnd_toEndOf="parent" @@ -96,10 +93,7 @@ android:id="@+id/messageBody" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginLeft="8dp" - android:layout_marginEnd="8dp" - android:layout_marginRight="8dp" + android:layout_marginHorizontal="8dp" android:layout_marginBottom="12dp" android:singleLine="true" android:textAppearance="@style/NavView.TextView.Helper" diff --git a/app/src/main/res/layout/messages_list_item.xml b/app/src/main/res/layout/messages_list_item.xml index 686e9dce..d8c1b8d8 100644 --- a/app/src/main/res/layout/messages_list_item.xml +++ b/app/src/main/res/layout/messages_list_item.xml @@ -39,10 +39,7 @@ android:id="@+id/messageSubject" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginLeft="8dp" - android:layout_marginEnd="8dp" - android:layout_marginRight="8dp" + android:layout_marginHorizontal="8dp" android:singleLine="true" android:textStyle="normal" android:textAppearance="@style/NavView.TextView.Helper" @@ -73,10 +70,7 @@ android:id="@+id/messageBody" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginLeft="8dp" - android:layout_marginEnd="8dp" - android:layout_marginRight="8dp" + android:layout_marginHorizontal="8dp" android:layout_marginBottom="12dp" android:singleLine="true" android:textAppearance="@style/NavView.TextView.Helper" diff --git a/app/src/main/res/layout/row_attendance_item.xml b/app/src/main/res/layout/row_attendance_item.xml index d6e6bfd2..0e68aa70 100644 --- a/app/src/main/res/layout/row_attendance_item.xml +++ b/app/src/main/res/layout/row_attendance_item.xml @@ -43,10 +43,7 @@ android:id="@+id/attendanceSubject" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginLeft="8dp" - android:layout_marginEnd="8dp" - android:layout_marginRight="8dp" + android:layout_marginHorizontal="8dp" android:ellipsize="end" android:fontFamily="sans-serif-medium" android:singleLine="true" @@ -59,10 +56,7 @@ android:id="@+id/attendanceTeacher" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginLeft="8dp" - android:layout_marginEnd="8dp" - android:layout_marginRight="8dp" + android:layout_marginHorizontal="8dp" android:ellipsize="end" android:singleLine="true" android:textAppearance="@style/NavView.TextView.Helper" diff --git a/app/src/main/res/layout/row_dialog_event_list_item.xml b/app/src/main/res/layout/row_dialog_event_list_item.xml index 1ac0f53b..111313d8 100644 --- a/app/src/main/res/layout/row_dialog_event_list_item.xml +++ b/app/src/main/res/layout/row_dialog_event_list_item.xml @@ -80,11 +80,8 @@ android:id="@+id/eventListItemTeacherName" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginLeft="8dp" + android:layout_marginHorizontal="8dp" android:layout_marginTop="4dp" - android:layout_marginEnd="8dp" - android:layout_marginRight="8dp" android:ellipsize="end" android:maxLines="2" android:textAppearance="@style/NavView.TextView.Helper" @@ -134,11 +131,8 @@ android:id="@+id/eventListItemSharedBy" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginLeft="8dp" + android:layout_marginHorizontal="8dp" android:layout_marginTop="8dp" - android:layout_marginEnd="8dp" - android:layout_marginRight="8dp" android:ellipsize="end" android:maxLines="1" tools:text="{cmd-share-variant} przez Jan Kowalski" diff --git a/app/src/main/res/layout/row_dialog_teacher_absence_item.xml b/app/src/main/res/layout/row_dialog_teacher_absence_item.xml index 8d303464..0d64770d 100644 --- a/app/src/main/res/layout/row_dialog_teacher_absence_item.xml +++ b/app/src/main/res/layout/row_dialog_teacher_absence_item.xml @@ -10,9 +10,8 @@ - \ No newline at end of file + diff --git a/app/src/main/res/layout/timetable_free_day.xml b/app/src/main/res/layout/timetable_free_day.xml index bd434b6e..0cc275a2 100644 --- a/app/src/main/res/layout/timetable_free_day.xml +++ b/app/src/main/res/layout/timetable_free_day.xml @@ -32,8 +32,7 @@ android:id="@+id/freeDayText" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginStart="32dp" - android:layout_marginEnd="32dp" + android:layout_marginHorizontal="32dp" android:gravity="center" android:textSize="16sp" tools:text="Dzień wolny dla szkoły z puli dyrektorskiej z okazji obchodów Światowego Dnia Wtorku w mieście Poznań i na przedmieśiach" /> @@ -45,4 +44,4 @@ android:layout_marginTop="16dp" android:text="@string/timetable_free_day_show" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/timetable_lesson.xml b/app/src/main/res/layout/timetable_lesson.xml index fc39e799..3c998027 100644 --- a/app/src/main/res/layout/timetable_lesson.xml +++ b/app/src/main/res/layout/timetable_lesson.xml @@ -75,10 +75,7 @@ android:layout_width="12dp" android:layout_height="12dp" android:layout_gravity="center_vertical" - android:layout_marginStart="8dp" - android:layout_marginLeft="8dp" - android:layout_marginEnd="8dp" - android:layout_marginRight="8dp" + android:layout_marginHorizontal="8dp" android:visibility="@{unread ? View.VISIBLE : View.GONE}" android:background="@drawable/unread_red_circle" /> diff --git a/app/src/main/res/layout/timetable_no_timetable.xml b/app/src/main/res/layout/timetable_no_timetable.xml index 8c80ee02..ce3bf187 100644 --- a/app/src/main/res/layout/timetable_no_timetable.xml +++ b/app/src/main/res/layout/timetable_no_timetable.xml @@ -25,9 +25,8 @@ @@ -48,4 +47,4 @@ tools:text="@string/timetable_no_timetable_week" /> - \ No newline at end of file + From 37879ca07ee243a451b9de5391ae7f64904d1060 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 25 Mar 2021 12:48:28 +0100 Subject: [PATCH 029/113] [Layout] Migrate marginLeft/marginRight to marginHorizontal. --- app/src/main/res/layout/card_home.xml | 3 +-- .../main/res/layout/card_home_timetable.xml | 3 +-- app/src/main/res/layout/dialog_day.xml | 15 ++++------- app/src/main/res/layout/dialog_event_list.xml | 9 +++---- .../main/res/layout/dialog_event_manual.xml | 8 +++--- .../main/res/layout/dialog_grade_details.xml | 3 +-- .../main/res/layout/dialog_lesson_details.xml | 15 ++++------- app/src/main/res/layout/event_list_item.xml | 3 +-- .../main/res/layout/fragment_attendance.xml | 15 ++++------- .../main/res/layout/fragment_behaviour.xml | 9 +++---- app/src/main/res/layout/fragment_feedback.xml | 6 ++--- .../res/layout/fragment_grades_editor.xml | 27 +++++++------------ app/src/main/res/layout/fragment_loading.xml | 5 ++-- app/src/main/res/layout/message_fragment.xml | 21 +++++---------- app/src/main/res/layout/messages_details.xml | 24 ++++++----------- app/src/main/res/layout/recaptcha_view.xml | 6 ++--- .../res/layout/row_grades_editor_item.xml | 3 +-- 17 files changed, 59 insertions(+), 116 deletions(-) diff --git a/app/src/main/res/layout/card_home.xml b/app/src/main/res/layout/card_home.xml index 60e58ec3..d2c42753 100644 --- a/app/src/main/res/layout/card_home.xml +++ b/app/src/main/res/layout/card_home.xml @@ -6,9 +6,8 @@ diff --git a/app/src/main/res/layout/card_home_timetable.xml b/app/src/main/res/layout/card_home_timetable.xml index 842e5b51..0df38a7d 100644 --- a/app/src/main/res/layout/card_home_timetable.xml +++ b/app/src/main/res/layout/card_home_timetable.xml @@ -239,8 +239,7 @@ style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginLeft="4dp" - android:layout_marginRight="4dp" + android:layout_marginHorizontal="4dp" android:visibility="gone" tools:max="2700" tools:progress="780" diff --git a/app/src/main/res/layout/dialog_day.xml b/app/src/main/res/layout/dialog_day.xml index d8c108ac..6461f14d 100644 --- a/app/src/main/res/layout/dialog_day.xml +++ b/app/src/main/res/layout/dialog_day.xml @@ -23,8 +23,7 @@ android:id="@+id/dayDate" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginLeft="8dp" - android:layout_marginRight="8dp" + android:layout_marginHorizontal="8dp" android:layout_marginBottom="8dp" android:textAppearance="@style/NavView.TextView.Title" android:textIsSelectable="true" @@ -34,8 +33,7 @@ android:id="@+id/lessonsInfo" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginLeft="8dp" - android:layout_marginRight="8dp" + android:layout_marginHorizontal="8dp" android:layout_marginBottom="8dp" android:textAppearance="@style/NavView.TextView.Helper" android:textIsSelectable="true" @@ -54,9 +52,8 @@ layout="@layout/row_lesson_change_item" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginLeft="8dp" + android:layout_marginHorizontal="8dp" android:layout_marginTop="5dp" - android:layout_marginRight="8dp" android:layout_marginBottom="5dp" android:visibility="gone" tools:visibility="visible" /> @@ -73,10 +70,9 @@ layout="@layout/row_teacher_absence_item" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginHorizontal="8dp" android:layout_marginTop="5dp" android:layout_marginBottom="5dp" - android:layout_marginLeft="8dp" - android:layout_marginRight="8dp" android:visibility="gone" tools:visibility="visible" /> @@ -85,8 +81,7 @@ android:id="@+id/eventsNoData" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginLeft="8dp" - android:layout_marginRight="8dp" + android:layout_marginHorizontal="8dp" android:paddingVertical="16dp" android:orientation="vertical" android:visibility="gone" diff --git a/app/src/main/res/layout/dialog_event_list.xml b/app/src/main/res/layout/dialog_event_list.xml index d321844b..0b49bdd4 100644 --- a/app/src/main/res/layout/dialog_event_list.xml +++ b/app/src/main/res/layout/dialog_event_list.xml @@ -16,10 +16,9 @@ layout="@layout/row_lesson_change_item" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginHorizontal="24dp" android:layout_marginTop="5dp" android:layout_marginBottom="5dp" - android:layout_marginLeft="24dp" - android:layout_marginRight="24dp" android:visibility="gone" tools:visibility="visible" /> @@ -28,10 +27,9 @@ layout="@layout/row_teacher_absence_item" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginHorizontal="24dp" android:layout_marginTop="5dp" android:layout_marginBottom="5dp" - android:layout_marginLeft="24dp" - android:layout_marginRight="24dp" android:visibility="gone" tools:visibility="visible" /> @@ -39,8 +37,7 @@ android:id="@+id/eventListLessonDetails" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginLeft="24dp" - android:layout_marginRight="24dp" + android:layout_marginHorizontal="24dp" android:orientation="vertical"> @@ -231,4 +229,4 @@ android:text="@string/dialog_event_manual_no_subject" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/dialog_grade_details.xml b/app/src/main/res/layout/dialog_grade_details.xml index b53ff721..c97e9fd8 100644 --- a/app/src/main/res/layout/dialog_grade_details.xml +++ b/app/src/main/res/layout/dialog_grade_details.xml @@ -260,8 +260,7 @@ android:id="@+id/gradeHistoryNest" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginLeft="-8dp" - android:layout_marginRight="-8dp" + android:layout_marginHorizontal="-8dp" android:visibility="@{historyVisible ? View.VISIBLE : View.GONE}"> @@ -131,9 +130,8 @@ android:id="@+id/shiftedLayout" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginLeft="8dp" + android:layout_marginHorizontal="8dp" android:layout_marginTop="8dp" - android:layout_marginRight="8dp" android:baselineAligned="false" android:gravity="center_vertical" android:orientation="horizontal"> @@ -159,9 +157,8 @@ @@ -231,8 +228,7 @@ @@ -302,8 +298,7 @@ android:id="@+id/eventsNoData" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginLeft="8dp" - android:layout_marginRight="8dp" + android:layout_marginHorizontal="8dp" android:paddingVertical="16dp" android:orientation="vertical" android:visibility="gone" diff --git a/app/src/main/res/layout/event_list_item.xml b/app/src/main/res/layout/event_list_item.xml index f8f42ef9..24445327 100644 --- a/app/src/main/res/layout/event_list_item.xml +++ b/app/src/main/res/layout/event_list_item.xml @@ -90,8 +90,7 @@ android:layout_width="32dp" android:layout_height="32dp" android:layout_gravity="top" - android:layout_marginLeft="4dp" - android:layout_marginRight="4dp" + android:layout_marginHorizontal="4dp" android:visibility="gone" app:iiv_color="@color/md_green_500" app:iiv_icon="cmd-check" diff --git a/app/src/main/res/layout/fragment_attendance.xml b/app/src/main/res/layout/fragment_attendance.xml index da464f3b..5d89279f 100644 --- a/app/src/main/res/layout/fragment_attendance.xml +++ b/app/src/main/res/layout/fragment_attendance.xml @@ -59,8 +59,7 @@ android:id="@+id/presentCount" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginLeft="5dp" - android:layout_marginRight="5dp" + android:layout_marginHorizontal="5dp" android:textStyle="bold" tools:text="0" /> @@ -79,8 +78,7 @@ android:id="@+id/absentCount" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginLeft="5dp" - android:layout_marginRight="5dp" + android:layout_marginHorizontal="5dp" android:textStyle="bold" tools:text="0" /> @@ -99,8 +97,7 @@ android:id="@+id/absentUnexcusedCount" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginLeft="5dp" - android:layout_marginRight="5dp" + android:layout_marginHorizontal="5dp" android:textStyle="bold" tools:text="0" /> @@ -119,8 +116,7 @@ android:id="@+id/belatedCount" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginLeft="5dp" - android:layout_marginRight="5dp" + android:layout_marginHorizontal="5dp" android:textStyle="bold" tools:text="0" /> @@ -139,8 +135,7 @@ android:id="@+id/releasedCount" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginLeft="5dp" - android:layout_marginRight="5dp" + android:layout_marginHorizontal="5dp" android:textStyle="bold" tools:text="8" /> diff --git a/app/src/main/res/layout/fragment_behaviour.xml b/app/src/main/res/layout/fragment_behaviour.xml index ddd9faed..79b8554e 100644 --- a/app/src/main/res/layout/fragment_behaviour.xml +++ b/app/src/main/res/layout/fragment_behaviour.xml @@ -42,8 +42,7 @@ android:id="@+id/noticesPraisesCount" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginLeft="5dp" - android:layout_marginRight="5dp" + android:layout_marginHorizontal="5dp" android:textStyle="bold" tools:text="0" /> @@ -62,8 +61,7 @@ android:id="@+id/noticesWarningsCount" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginLeft="5dp" - android:layout_marginRight="5dp" + android:layout_marginHorizontal="5dp" android:textStyle="bold" tools:text="0" /> @@ -82,8 +80,7 @@ android:id="@+id/noticesOtherCount" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginLeft="5dp" - android:layout_marginRight="5dp" + android:layout_marginHorizontal="5dp" android:textStyle="bold" tools:text="0" /> diff --git a/app/src/main/res/layout/fragment_feedback.xml b/app/src/main/res/layout/fragment_feedback.xml index 64aa6a4f..d4891dd6 100644 --- a/app/src/main/res/layout/fragment_feedback.xml +++ b/app/src/main/res/layout/fragment_feedback.xml @@ -43,9 +43,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="end" - android:layout_marginLeft="8dp" + android:layout_marginHorizontal="8dp" android:layout_marginTop="8dp" - android:layout_marginRight="8dp" android:text="@string/feedback_faq_button" android:visibility="gone" /> @@ -112,8 +111,7 @@ diff --git a/app/src/main/res/layout/fragment_grades_editor.xml b/app/src/main/res/layout/fragment_grades_editor.xml index df49ef4d..242b8a02 100644 --- a/app/src/main/res/layout/fragment_grades_editor.xml +++ b/app/src/main/res/layout/fragment_grades_editor.xml @@ -10,9 +10,8 @@ android:id="@+id/subjectName" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginLeft="8dp" + android:layout_marginHorizontal="8dp" android:layout_marginTop="8dp" - android:layout_marginRight="8dp" android:textSize="24sp" android:textAppearance="@style/NavView.TextView.Title" tools:text="geografia" /> @@ -21,9 +20,8 @@ android:id="@+id/semesterName" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginLeft="8dp" + android:layout_marginHorizontal="8dp" android:layout_marginTop="8dp" - android:layout_marginRight="8dp" android:textAppearance="@style/NavView.TextView.Subtitle" tools:text="Semestr 1" /> @@ -36,8 +34,7 @@ @@ -152,9 +145,8 @@ android:id="@+id/addGrade" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginLeft="8dp" + android:layout_marginHorizontal="8dp" android:layout_marginTop="8dp" - android:layout_marginRight="8dp" android:minHeight="0dp" android:text="@string/grades_editor_add_grade" /> @@ -162,9 +154,8 @@ android:id="@+id/restoreGrades" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginLeft="8dp" + android:layout_marginHorizontal="8dp" android:layout_marginTop="8dp" - android:layout_marginRight="8dp" android:minHeight="0dp" android:text="@string/grades_editor_restore" /> diff --git a/app/src/main/res/layout/fragment_loading.xml b/app/src/main/res/layout/fragment_loading.xml index 1c740c19..b6e4ae34 100644 --- a/app/src/main/res/layout/fragment_loading.xml +++ b/app/src/main/res/layout/fragment_loading.xml @@ -22,11 +22,10 @@ - \ No newline at end of file + diff --git a/app/src/main/res/layout/message_fragment.xml b/app/src/main/res/layout/message_fragment.xml index 53778e8a..4a475824 100644 --- a/app/src/main/res/layout/message_fragment.xml +++ b/app/src/main/res/layout/message_fragment.xml @@ -153,9 +153,8 @@ @@ -170,9 +169,8 @@ android:id="@+id/attachmentsTitle" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginLeft="16dp" + android:layout_marginHorizontal="16dp" android:layout_marginTop="8dp" - android:layout_marginRight="16dp" android:text="Załączniki:" android:textAppearance="@style/NavView.TextView.Subtitle" /> @@ -186,8 +184,7 @@ @@ -186,9 +185,8 @@ android:id="@+id/messageAttachmentsTitle" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginLeft="16dp" + android:layout_marginHorizontal="16dp" android:layout_marginTop="8dp" - android:layout_marginRight="16dp" android:text="Załączniki:" android:textAppearance="@style/NavView.TextView.Subtitle" /> @@ -226,8 +224,7 @@ android:layout_width="18dp" android:layout_height="18dp" android:layout_gravity="center_vertical|end" - android:layout_marginLeft="8dp" - android:layout_marginRight="8dp" /> + android:layout_marginHorizontal="8dp" /> @@ -255,8 +252,7 @@ android:layout_width="18dp" android:layout_height="18dp" android:layout_gravity="center_vertical|end" - android:layout_marginLeft="8dp" - android:layout_marginRight="8dp" /> + android:layout_marginHorizontal="8dp" /> @@ -265,8 +261,7 @@ @@ -66,8 +65,7 @@ Date: Thu, 25 Mar 2021 12:51:37 +0100 Subject: [PATCH 030/113] [Layout] Migrate marginTop/marginBottom to marginVertical. --- app/src/main/res/layout/card_home.xml | 3 +-- app/src/main/res/layout/card_home_timetable.xml | 6 ++---- app/src/main/res/layout/dialog_config_grades.xml | 6 ++---- app/src/main/res/layout/dialog_day.xml | 6 ++---- app/src/main/res/layout/dialog_event_list.xml | 6 ++---- app/src/main/res/layout/fragment_feedback.xml | 6 ++---- app/src/main/res/layout/message_fragment.xml | 3 +-- app/src/main/res/layout/messages_details.xml | 3 +-- app/src/main/res/layout/row_attendance_item.xml | 3 +-- app/src/main/res/layout/row_dialog_teacher_absence_item.xml | 3 +-- app/src/main/res/layout/row_login_profile_list_item.xml | 3 +-- app/src/main/res/layout/row_notices_item.xml | 3 +-- app/src/main/res/layout/row_timetable_item.xml | 6 ++---- .../main/res/layout/row_widget_notifications_big_item.xml | 6 ++---- .../res/layout/row_widget_notifications_dark_big_item.xml | 6 ++---- .../main/res/layout/row_widget_notifications_dark_item.xml | 6 ++---- app/src/main/res/layout/row_widget_notifications_item.xml | 6 ++---- app/src/main/res/layout/row_widget_timetable_big_item.xml | 6 ++---- .../main/res/layout/row_widget_timetable_dark_big_item.xml | 6 ++---- app/src/main/res/layout/row_widget_timetable_dark_item.xml | 6 ++---- app/src/main/res/layout/row_widget_timetable_item.xml | 6 ++---- app/src/main/res/layout/timetable_lesson.xml | 3 +-- 22 files changed, 36 insertions(+), 72 deletions(-) diff --git a/app/src/main/res/layout/card_home.xml b/app/src/main/res/layout/card_home.xml index d2c42753..f013726b 100644 --- a/app/src/main/res/layout/card_home.xml +++ b/app/src/main/res/layout/card_home.xml @@ -7,7 +7,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginHorizontal="16dp" - android:layout_marginTop="8dp" - android:layout_marginBottom="8dp" + android:layout_marginVertical="8dp" android:clickable="true" android:focusable="true" /> diff --git a/app/src/main/res/layout/card_home_timetable.xml b/app/src/main/res/layout/card_home_timetable.xml index 0df38a7d..88141c86 100644 --- a/app/src/main/res/layout/card_home_timetable.xml +++ b/app/src/main/res/layout/card_home_timetable.xml @@ -205,8 +205,7 @@ @@ -140,8 +139,7 @@ diff --git a/app/src/main/res/layout/dialog_day.xml b/app/src/main/res/layout/dialog_day.xml index 6461f14d..59fd7f8c 100644 --- a/app/src/main/res/layout/dialog_day.xml +++ b/app/src/main/res/layout/dialog_day.xml @@ -53,8 +53,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginHorizontal="8dp" - android:layout_marginTop="5dp" - android:layout_marginBottom="5dp" + android:layout_marginVertical="5dp" android:visibility="gone" tools:visibility="visible" /> @@ -71,8 +70,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginHorizontal="8dp" - android:layout_marginTop="5dp" - android:layout_marginBottom="5dp" + android:layout_marginVertical="5dp" android:visibility="gone" tools:visibility="visible" /> diff --git a/app/src/main/res/layout/dialog_event_list.xml b/app/src/main/res/layout/dialog_event_list.xml index 0b49bdd4..114d9c1c 100644 --- a/app/src/main/res/layout/dialog_event_list.xml +++ b/app/src/main/res/layout/dialog_event_list.xml @@ -17,8 +17,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginHorizontal="24dp" - android:layout_marginTop="5dp" - android:layout_marginBottom="5dp" + android:layout_marginVertical="5dp" android:visibility="gone" tools:visibility="visible" /> @@ -28,8 +27,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginHorizontal="24dp" - android:layout_marginTop="5dp" - android:layout_marginBottom="5dp" + android:layout_marginVertical="5dp" android:visibility="gone" tools:visibility="visible" /> diff --git a/app/src/main/res/layout/fragment_feedback.xml b/app/src/main/res/layout/fragment_feedback.xml index d4891dd6..79d1466d 100644 --- a/app/src/main/res/layout/fragment_feedback.xml +++ b/app/src/main/res/layout/fragment_feedback.xml @@ -103,8 +103,7 @@ android:id="@+id/chatLayout" android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_marginTop="8dp" - android:layout_marginBottom="8dp" + android:layout_marginVertical="8dp" android:orientation="vertical" android:visibility="visible"> @@ -119,8 +118,7 @@ android:id="@+id/chat_view" android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_marginTop="8dp" - android:layout_marginBottom="8dp" /> + android:layout_marginVertical="8dp" /> diff --git a/app/src/main/res/layout/message_fragment.xml b/app/src/main/res/layout/message_fragment.xml index 4a475824..ee6dfd85 100644 --- a/app/src/main/res/layout/message_fragment.xml +++ b/app/src/main/res/layout/message_fragment.xml @@ -138,8 +138,7 @@ android:id="@+id/body" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="8dp" - android:layout_marginBottom="8dp" + android:layout_marginVertical="8dp" android:minHeight="250dp" android:paddingHorizontal="16dp" android:textIsSelectable="true" diff --git a/app/src/main/res/layout/messages_details.xml b/app/src/main/res/layout/messages_details.xml index b0cbb487..5aa8f319 100644 --- a/app/src/main/res/layout/messages_details.xml +++ b/app/src/main/res/layout/messages_details.xml @@ -153,8 +153,7 @@ android:id="@+id/messageBody" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="8dp" - android:layout_marginBottom="8dp" + android:layout_marginVertical="8dp" android:autoLink="all" android:minHeight="250dp" android:paddingHorizontal="16dp" diff --git a/app/src/main/res/layout/row_attendance_item.xml b/app/src/main/res/layout/row_attendance_item.xml index 0e68aa70..af5ca544 100644 --- a/app/src/main/res/layout/row_attendance_item.xml +++ b/app/src/main/res/layout/row_attendance_item.xml @@ -70,10 +70,9 @@ android:id="@+id/attendanceTime" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginTop="0dp" + android:layout_marginVertical="0dp" android:layout_marginEnd="8dp" android:layout_marginRight="8dp" - android:layout_marginBottom="0dp" android:textAppearance="@style/NavView.TextView.Helper" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" diff --git a/app/src/main/res/layout/row_dialog_teacher_absence_item.xml b/app/src/main/res/layout/row_dialog_teacher_absence_item.xml index 0d64770d..0b8383d1 100644 --- a/app/src/main/res/layout/row_dialog_teacher_absence_item.xml +++ b/app/src/main/res/layout/row_dialog_teacher_absence_item.xml @@ -11,8 +11,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginHorizontal="8dp" - android:layout_marginTop="4dp" - android:layout_marginBottom="4dp" + android:layout_marginVertical="4dp" android:background="?selectableItemBackground" app:cardCornerRadius="5dp" app:cardElevation="4dp"> diff --git a/app/src/main/res/layout/row_login_profile_list_item.xml b/app/src/main/res/layout/row_login_profile_list_item.xml index 550034a3..3c222843 100644 --- a/app/src/main/res/layout/row_login_profile_list_item.xml +++ b/app/src/main/res/layout/row_login_profile_list_item.xml @@ -15,8 +15,7 @@ android:id="@+id/checkBox" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginTop="8dp" - android:layout_marginBottom="8dp" /> + android:layout_marginVertical="8dp" /> diff --git a/app/src/main/res/layout/row_timetable_item.xml b/app/src/main/res/layout/row_timetable_item.xml index d1df1893..0171ff67 100644 --- a/app/src/main/res/layout/row_timetable_item.xml +++ b/app/src/main/res/layout/row_timetable_item.xml @@ -11,8 +11,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginHorizontal="8dp" - android:layout_marginTop="4dp" - android:layout_marginBottom="4dp" + android:layout_marginVertical="4dp" android:background="?selectableItemBackground" app:cardCornerRadius="5dp" app:cardElevation="4dp"> @@ -142,8 +141,7 @@ @@ -48,4 +46,4 @@ android:textSize="14sp" tools:text="10:00 - 10:45" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/row_widget_notifications_dark_big_item.xml b/app/src/main/res/layout/row_widget_notifications_dark_big_item.xml index 3917cb91..fda1a2cb 100644 --- a/app/src/main/res/layout/row_widget_notifications_dark_big_item.xml +++ b/app/src/main/res/layout/row_widget_notifications_dark_big_item.xml @@ -1,6 +1,5 @@ @@ -48,4 +46,4 @@ android:textSize="14sp" tools:text="10:00 - 10:45" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/row_widget_notifications_dark_item.xml b/app/src/main/res/layout/row_widget_notifications_dark_item.xml index 3bb9a0c9..6426a4bb 100644 --- a/app/src/main/res/layout/row_widget_notifications_dark_item.xml +++ b/app/src/main/res/layout/row_widget_notifications_dark_item.xml @@ -1,6 +1,5 @@ @@ -48,4 +46,4 @@ android:textSize="11sp" tools:text="10:00 - 10:45" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/row_widget_notifications_item.xml b/app/src/main/res/layout/row_widget_notifications_item.xml index 3eb37e94..47d228b8 100644 --- a/app/src/main/res/layout/row_widget_notifications_item.xml +++ b/app/src/main/res/layout/row_widget_notifications_item.xml @@ -1,6 +1,5 @@ @@ -48,4 +46,4 @@ android:textSize="11sp" tools:text="10:00 - 10:45" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/row_widget_timetable_big_item.xml b/app/src/main/res/layout/row_widget_timetable_big_item.xml index 4543536e..003600b4 100644 --- a/app/src/main/res/layout/row_widget_timetable_big_item.xml +++ b/app/src/main/res/layout/row_widget_timetable_big_item.xml @@ -1,6 +1,5 @@ - \ No newline at end of file + diff --git a/app/src/main/res/layout/row_widget_timetable_dark_big_item.xml b/app/src/main/res/layout/row_widget_timetable_dark_big_item.xml index 794069a3..1e80afb6 100644 --- a/app/src/main/res/layout/row_widget_timetable_dark_big_item.xml +++ b/app/src/main/res/layout/row_widget_timetable_dark_big_item.xml @@ -1,6 +1,5 @@ - \ No newline at end of file + diff --git a/app/src/main/res/layout/row_widget_timetable_dark_item.xml b/app/src/main/res/layout/row_widget_timetable_dark_item.xml index 813f7186..77149eeb 100644 --- a/app/src/main/res/layout/row_widget_timetable_dark_item.xml +++ b/app/src/main/res/layout/row_widget_timetable_dark_item.xml @@ -1,6 +1,5 @@ - \ No newline at end of file + diff --git a/app/src/main/res/layout/row_widget_timetable_item.xml b/app/src/main/res/layout/row_widget_timetable_item.xml index 84942a94..c0383b1a 100644 --- a/app/src/main/res/layout/row_widget_timetable_item.xml +++ b/app/src/main/res/layout/row_widget_timetable_item.xml @@ -1,6 +1,5 @@ - \ No newline at end of file + diff --git a/app/src/main/res/layout/timetable_lesson.xml b/app/src/main/res/layout/timetable_lesson.xml index 3c998027..3b51a197 100644 --- a/app/src/main/res/layout/timetable_lesson.xml +++ b/app/src/main/res/layout/timetable_lesson.xml @@ -57,8 +57,7 @@ android:id="@+id/subjectName" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="4dp" - android:layout_marginBottom="4dp" + android:layout_marginVertical="4dp" android:layout_weight="1" android:ellipsize="end" android:fontFamily="sans-serif-light" From 2d01a8c4d4bb19fbfd2de51afdc69067ec978c90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 25 Mar 2021 12:59:42 +0100 Subject: [PATCH 031/113] [UI] Fix nightly badge background tint. --- app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt | 3 +++ app/src/main/res/layout/activity_szkolny.xml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt index de9b5f85..cdb9778f 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt @@ -317,6 +317,9 @@ class MainActivity : AppCompatActivity(), CoroutineScope { } else -> b.nightlyText.isVisible = false } + if (b.nightlyText.isVisible) { + b.nightlyText.background.setTintColor(0xa0ff0000.toInt()) + } navLoading = true diff --git a/app/src/main/res/layout/activity_szkolny.xml b/app/src/main/res/layout/activity_szkolny.xml index bdb2a6e7..2b35b431 100644 --- a/app/src/main/res/layout/activity_szkolny.xml +++ b/app/src/main/res/layout/activity_szkolny.xml @@ -40,13 +40,13 @@ android:layout_marginHorizontal="48dp" android:layout_marginVertical="8dp" android:background="@drawable/bg_rounded_4dp" - android:backgroundTint="#a0ff0000" android:fontFamily="sans-serif-light" android:gravity="center" android:padding="4dp" android:textAllCaps="true" android:textSize="12sp" android:textStyle="bold" + tools:backgroundTint="#a0ff0000" tools:text="Nightly\n20200503" /> From fdad2d9e1a3bbbae5f531a8fcc8f6fa7417cacf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 25 Mar 2021 13:06:23 +0100 Subject: [PATCH 032/113] [UI] Fix timetable lesson colors. --- app/src/main/res/drawable/bg_rounded_edittext_pressed.xml | 4 ++-- app/src/main/res/drawable/timetable_lesson_bg_light.xml | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/drawable/bg_rounded_edittext_pressed.xml b/app/src/main/res/drawable/bg_rounded_edittext_pressed.xml index 845307b9..b007ed77 100644 --- a/app/src/main/res/drawable/bg_rounded_edittext_pressed.xml +++ b/app/src/main/res/drawable/bg_rounded_edittext_pressed.xml @@ -5,5 +5,5 @@ - - \ No newline at end of file + + diff --git a/app/src/main/res/drawable/timetable_lesson_bg_light.xml b/app/src/main/res/drawable/timetable_lesson_bg_light.xml index 7a17b6cd..39d48096 100644 --- a/app/src/main/res/drawable/timetable_lesson_bg_light.xml +++ b/app/src/main/res/drawable/timetable_lesson_bg_light.xml @@ -4,4 +4,5 @@ - \ No newline at end of file + + From ae6af77aefd6cb69f55e637df5a41aea0a9b59dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 25 Mar 2021 13:13:11 +0100 Subject: [PATCH 033/113] [UI] Fix message buttons margin. --- app/src/main/res/layout/message_fragment.xml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/layout/message_fragment.xml b/app/src/main/res/layout/message_fragment.xml index ee6dfd85..b368e671 100644 --- a/app/src/main/res/layout/message_fragment.xml +++ b/app/src/main/res/layout/message_fragment.xml @@ -177,14 +177,13 @@ android:id="@+id/attachmentsFragment" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginHorizontal="8dp" - android:layout_marginBottom="8dp"/> + android:layout_marginHorizontal="8dp" /> From 4045da7fc503c0a4595a5336afad9b35cc790522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 25 Mar 2021 13:19:52 +0100 Subject: [PATCH 034/113] [App] Disable TLSv1.3 requirement for SSLProvider. --- .../java/pl/szczodrzynski/edziennik/App.kt | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/App.kt b/app/src/main/java/pl/szczodrzynski/edziennik/App.kt index d8a2ec6a..e64b33cb 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/App.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/App.kt @@ -190,12 +190,18 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope { withContext(Dispatchers.Default) { config.migrate(this@App) - SSLProvider.install(applicationContext, downloadIfNeeded = true, supportTls13 = true, onFinish = { - buildHttp() - }, onError = { - Timber.e("Failed to install SSLProvider: $it") - it.printStackTrace() - }) + SSLProvider.install( + applicationContext, + downloadIfNeeded = true, + supportTls13 = false, + onFinish = { + buildHttp() + }, + onError = { + Timber.e("Failed to install SSLProvider: $it") + it.printStackTrace() + } + ) if (config.devModePassword != null) checkDevModePassword() From 0f84732f80fc847c57e432c8f8b86b9627376ec3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 25 Mar 2021 15:50:14 +0100 Subject: [PATCH 035/113] [UI/Settings] Add new profile config dialog. Implement choosing background images. --- app/build.gradle | 2 +- .../szczodrzynski/edziennik/MainActivity.kt | 55 ++--- .../edziennik/MainActivityRequestHandler.kt | 205 ++++++++++++++++++ .../ui/dialogs/profile/ProfileConfigDialog.kt | 88 ++++++++ .../ProfileRemoveDialog.kt | 6 +- .../dialogs/sync/RegistrationConfigDialog.kt | 10 +- .../ui/modules/debug/LabPageFragment.kt | 2 +- .../modules/settings/SettingsNewFragment.java | 4 +- .../ui/modules/settings/SettingsUtil.kt | 33 +-- .../settings/cards/SettingsProfileCard.kt | 23 +- .../settings/cards/SettingsThemeCard.kt | 56 ++++- .../main/res/layout/dialog_profile_config.xml | 107 +++++++++ .../mal_material_about_profile_item.xml | 2 +- app/src/main/res/values/strings.xml | 3 + 14 files changed, 525 insertions(+), 71 deletions(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/MainActivityRequestHandler.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/profile/ProfileConfigDialog.kt rename app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/{settings => profile}/ProfileRemoveDialog.kt (95%) create mode 100644 app/src/main/res/layout/dialog_profile_config.xml diff --git a/app/build.gradle b/app/build.gradle index 1766c3bf..15d7cdff 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -129,7 +129,7 @@ dependencies { implementation "com.mikepenz:iconics-core:5.2.8" implementation "com.mikepenz:iconics-views:5.2.8" implementation "com.mikepenz:community-material-typeface:5.8.55.0-kotlin@aar" - implementation "eu.szkolny:szkolny-font:1.2" + implementation "eu.szkolny:szkolny-font:1.3" // Other dependencies implementation "cat.ereza:customactivityoncrash:2.3.0" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt index 10caf080..971a46d2 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt @@ -10,7 +10,6 @@ import android.graphics.BitmapFactory import android.graphics.drawable.BitmapDrawable import android.os.Build import android.os.Bundle -import android.os.Environment import android.provider.Settings import android.view.Gravity import android.view.View @@ -56,7 +55,7 @@ import pl.szczodrzynski.edziennik.ui.dialogs.ServerMessageDialog import pl.szczodrzynski.edziennik.ui.dialogs.UpdateAvailableDialog import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog -import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog +import pl.szczodrzynski.edziennik.ui.dialogs.profile.ProfileRemoveDialog import pl.szczodrzynski.edziennik.ui.dialogs.sync.SyncViewListDialog import pl.szczodrzynski.edziennik.ui.modules.agenda.AgendaFragment import pl.szczodrzynski.edziennik.ui.modules.announcements.AnnouncementsFragment @@ -98,7 +97,6 @@ import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem import pl.szczodrzynski.navlib.drawer.NavDrawer import pl.szczodrzynski.navlib.drawer.items.DrawerPrimaryItem -import java.io.File import java.io.IOException import java.util.* import kotlin.coroutines.CoroutineContext @@ -111,8 +109,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope { const val TAG = "MainActivity" - const val REQUEST_LOGIN_ACTIVITY = 20222 - const val DRAWER_PROFILE_ADD_NEW = 200 const val DRAWER_PROFILE_SYNC_ALL = 201 const val DRAWER_PROFILE_EXPORT_DATA = 202 @@ -264,6 +260,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope { val bottomSheet: NavBottomSheet by lazy { navView.bottomSheet } val mainSnackbar: MainSnackbar by lazy { MainSnackbar(this) } val errorSnackbar: ErrorSnackbar by lazy { ErrorSnackbar(this) } + val requestHandler by lazy { MainActivityRequestHandler(this) } val swipeRefreshLayout: SwipeRefreshLayoutNoTouch by lazy { b.swipeRefreshLayout } @@ -479,28 +476,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope { } // APP BACKGROUND - if (app.config.ui.appBackground != null) { - try { - app.config.ui.appBackground?.let { - var bg = it - val bgDir = File(Environment.getExternalStoragePublicDirectory("Szkolny.eu"), "bg") - if (bgDir.exists()) { - val files = bgDir.listFiles() - val r = Random() - val i = r.nextInt(files.size) - bg = files[i].toString() - } - val linearLayout = b.root - if (bg.endsWith(".gif")) { - linearLayout.background = GifDrawable(bg) - } else { - linearLayout.background = BitmapDrawable.createFromPath(bg) - } - } - } catch (e: IOException) { - e.printStackTrace() - } - } + setAppBackground() // IT'S WINTER MY DUDES val today = Date.getToday() @@ -590,7 +566,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope { private var profileSettingClickListener = { id: Int, view: View? -> when (id) { DRAWER_PROFILE_ADD_NEW -> { - startActivityForResult(Intent(this, LoginActivity::class.java), REQUEST_LOGIN_ACTIVITY) + requestHandler.requestLogin() } DRAWER_PROFILE_SYNC_ALL -> { EdziennikTask.sync().enqueue(this) @@ -838,7 +814,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope { handleIntent(intent?.extras) } } - private fun handleIntent(extras: Bundle?) { + fun handleIntent(extras: Bundle?) { d(TAG, "handleIntent() {") extras?.keySet()?.forEach { key -> @@ -996,13 +972,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope { } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) - if (requestCode == REQUEST_LOGIN_ACTIVITY) { - if (!app.config.loginFinished) - finish() - else { - handleIntent(data?.extras) - } - } + requestHandler.handleResult(requestCode, resultCode, data) } /* _ _ _ _ _ @@ -1228,6 +1198,19 @@ class MainActivity : AppCompatActivity(), CoroutineScope { }, 3000) } + fun setAppBackground() { + try { + b.root.background = app.config.ui.appBackground?.let { + if (it.endsWith(".gif")) + GifDrawable(it) + else + BitmapDrawable.createFromPath(it) + } + } catch (e: IOException) { + e.printStackTrace() + } + } + /* _____ _ _ | __ \ (_) | | | | |_ __ __ ___ _____ _ __ _| |_ ___ _ __ ___ ___ diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivityRequestHandler.kt b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivityRequestHandler.kt new file mode 100644 index 00000000..3f086a44 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivityRequestHandler.kt @@ -0,0 +1,205 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-23. + */ + +package pl.szczodrzynski.edziennik + +import android.app.Activity +import android.content.Intent +import android.net.Uri +import android.provider.OpenableColumns +import com.theartofdev.edmodo.cropper.CropImage +import com.theartofdev.edmodo.cropper.CropImageView +import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity +import java.io.File +import java.io.FileOutputStream + +class MainActivityRequestHandler(val activity: MainActivity) { + companion object { + private const val REQUEST_LOGIN_ACTIVITY = 2000 + private const val REQUEST_FILE_HEADER_BACKGROUND = 3000 + private const val REQUEST_FILE_APP_BACKGROUND = 4000 + private const val REQUEST_FILE_PROFILE_IMAGE = 5000 + private const val REQUEST_CROP_HEADER_BACKGROUND = 3100 + private const val REQUEST_CROP_APP_BACKGROUND = 4100 + private const val REQUEST_CROP_PROFILE_IMAGE = 5100 + } + + private val app = activity.app + private val requestData = mutableMapOf() + private val listeners = mutableMapOf Unit>() + + fun requestLogin() = activity.startActivityForResult( + Intent(activity, LoginActivity::class.java), + REQUEST_LOGIN_ACTIVITY + ) + + fun requestHeaderBackground(listener: (Any?) -> Unit) { + listeners[REQUEST_FILE_HEADER_BACKGROUND] = listener + activity.startActivityForResult( + CropImage.getPickImageChooserIntent( + activity, + activity.getString(R.string.pick_image_intent_chooser_title), + true, + true + ), + REQUEST_FILE_HEADER_BACKGROUND + ) + } + + fun requestAppBackground(listener: (Any?) -> Unit) { + listeners[REQUEST_FILE_APP_BACKGROUND] = listener + activity.startActivityForResult( + CropImage.getPickImageChooserIntent( + activity, + activity.getString(R.string.pick_image_intent_chooser_title), + true, + true + ), + REQUEST_FILE_APP_BACKGROUND + ) + } + + fun requestProfileImage(profile: Profile, listener: (Any?) -> Unit) { + listeners[REQUEST_FILE_PROFILE_IMAGE] = listener + requestData[REQUEST_FILE_PROFILE_IMAGE] = profile + activity.startActivityForResult( + CropImage.getPickImageChooserIntent( + activity, + activity.getString(R.string.pick_image_intent_chooser_title), + true, + true + ), + REQUEST_FILE_PROFILE_IMAGE + ) + } + + private fun getFileInfo(uri: Uri): Pair { + val cursor = activity.contentResolver.query( + uri, + null, + null, + null, + null, + null + ) + + return cursor?.use { + if (it.moveToFirst()) { + val name = it.getString(it.getColumnIndex(OpenableColumns.DISPLAY_NAME)) + val mimeIndex = it.getColumnIndex("mime_type") + val mimeType = if (mimeIndex != -1) it.getString(mimeIndex) else null + + name to mimeType + } + else + null + } ?: "unknown" to null + } + + private fun shouldCrop(uri: Uri): Boolean { + val (filename, mimeType) = getFileInfo(uri) + return !filename.endsWith(".gif") && mimeType?.endsWith("/gif") != true + } + + private fun saveFile(uri: Uri, name: String): String { + val (filename, _) = getFileInfo(uri) + val extension = filename.substringAfterLast('.') + val file = File(activity.filesDir, "$name.$extension") + activity.contentResolver.openInputStream(uri)?.use { input -> + FileOutputStream(file).use { output -> + input.copyTo(output) + } + } + return file.absolutePath + } + + fun handleResult(requestCode: Int, resultCode: Int, data: Intent?) { + if (resultCode != Activity.RESULT_OK) + return + var uri = data?.data + when (requestCode) { + REQUEST_LOGIN_ACTIVITY -> { + if (!app.config.loginFinished) + activity.finish() + else { + activity.handleIntent(data?.extras) + } + } + REQUEST_FILE_HEADER_BACKGROUND -> { + if (uri == null) + return // TODO: 2021-03-24 if the app returns no data + if (shouldCrop(uri)) { + val intent = CropImage.activity(uri) + .setAspectRatio(512, 288) + .setGuidelines(CropImageView.Guidelines.ON_TOUCH) + .setAllowFlipping(true) + .setAllowRotation(true) + .setRequestedSize(512, 288) + .getIntent(activity) + activity.startActivityForResult(intent, REQUEST_CROP_HEADER_BACKGROUND) + } else { + val path = saveFile(uri, "header") + app.config.ui.headerBackground = path + listeners.remove(REQUEST_FILE_HEADER_BACKGROUND)?.invoke(path) + } + } + REQUEST_FILE_APP_BACKGROUND -> { + if (uri == null) + return + if (shouldCrop(uri)) { + val intent = CropImage.activity(uri) + .setGuidelines(CropImageView.Guidelines.ON_TOUCH) + .setAllowFlipping(true) + .setAllowRotation(true) + .getIntent(activity) + activity.startActivityForResult(intent, REQUEST_CROP_APP_BACKGROUND) + } else { + val path = saveFile(uri, "background") + app.config.ui.appBackground = path + listeners.remove(REQUEST_FILE_APP_BACKGROUND)?.invoke(path) + } + } + REQUEST_FILE_PROFILE_IMAGE -> { + if (uri == null) + return + if (shouldCrop(uri)) { + val intent = CropImage.activity(uri) + .setAspectRatio(1, 1) + .setCropShape(CropImageView.CropShape.OVAL) + .setGuidelines(CropImageView.Guidelines.ON_TOUCH) + .setAllowFlipping(true) + .setAllowRotation(true) + .setRequestedSize(512, 512) + .getIntent(activity) + activity.startActivityForResult(intent, REQUEST_CROP_PROFILE_IMAGE) + } else { + val profile = requestData.remove(REQUEST_FILE_PROFILE_IMAGE) as? Profile ?: return + val path = saveFile(uri, "profile${profile.id}") + profile.image = path + listeners.remove(REQUEST_FILE_PROFILE_IMAGE)?.invoke(profile) + } + } + REQUEST_CROP_HEADER_BACKGROUND -> { + uri = CropImage.getActivityResult(data)?.uri ?: return + val path = saveFile(uri, "header") + app.config.ui.headerBackground = path + listeners.remove(REQUEST_FILE_HEADER_BACKGROUND)?.invoke(path) + } + REQUEST_CROP_APP_BACKGROUND -> { + uri = CropImage.getActivityResult(data)?.uri ?: return + val path = saveFile(uri, "background") + app.config.ui.appBackground = path + listeners.remove(REQUEST_FILE_APP_BACKGROUND)?.invoke(path) + } + REQUEST_CROP_PROFILE_IMAGE -> { + uri = CropImage.getActivityResult(data)?.uri ?: return + val profile = requestData.remove(REQUEST_FILE_PROFILE_IMAGE) as? Profile ?: return + val path = saveFile(uri, "profile${profile.id}") + profile.image = path + listeners.remove(REQUEST_FILE_PROFILE_IMAGE)?.invoke(profile) + } + } + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/profile/ProfileConfigDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/profile/ProfileConfigDialog.kt new file mode 100644 index 00000000..6d51d3a1 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/profile/ProfileConfigDialog.kt @@ -0,0 +1,88 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-23. + */ + +package pl.szczodrzynski.edziennik.ui.dialogs.profile + +import androidx.appcompat.app.AlertDialog +import androidx.core.widget.addTextChangedListener +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import pl.szczodrzynski.edziennik.* +import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.databinding.DialogProfileConfigBinding +import kotlin.coroutines.CoroutineContext + +class ProfileConfigDialog( + val activity: MainActivity, + val profile: Profile, + val onProfileSaved: ((profile: Profile) -> Unit)? = null, + val onShowListener: ((tag: String) -> Unit)? = null, + val onDismissListener: ((tag: String) -> Unit)? = null +) : CoroutineScope { + companion object { + private const val TAG = "ProfileConfigDialog" + } + + private lateinit var app: App + private lateinit var b: DialogProfileConfigBinding + private lateinit var dialog: AlertDialog + + private val job = Job() + override val coroutineContext: CoroutineContext + get() = job + Dispatchers.Main + + // local variables go here + private var profileChanged = false + private var profileRemoved = false + + init { run { + if (activity.isFinishing) + return@run + onShowListener?.invoke(TAG) + app = activity.applicationContext as App + b = DialogProfileConfigBinding.inflate(activity.layoutInflater) + dialog = MaterialAlertDialogBuilder(activity) + .setView(b.root) + .setPositiveButton(R.string.close, null) + .setOnDismissListener { + if (!profileRemoved && profileChanged) { + app.profileSave(profile) + onProfileSaved?.invoke(profile) + } + onDismissListener?.invoke(TAG) + } + .show() + + b.profile = profile + profile.applyImageTo(b.image) + + b.nameEdit.addTextChangedListener { + profileChanged = true + } + + b.syncSwitch.onChange { _, _ -> + profileChanged = true + } + + b.imageButton.onClick { + activity.requestHandler.requestProfileImage(profile) { + val profile = it as? Profile ?: return@requestProfileImage + if (this@ProfileConfigDialog.profile == profile) { + profileChanged = true + b.profile = profile + profile.applyImageTo(b.image) + } + } + } + + b.logoutButton.onClick { + ProfileRemoveDialog(activity, profile.id, profile.name) { + profileRemoved = true + dialog.dismiss() + } + } + }} +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/ProfileRemoveDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/profile/ProfileRemoveDialog.kt similarity index 95% rename from app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/ProfileRemoveDialog.kt rename to app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/profile/ProfileRemoveDialog.kt index 1fa16230..7071f00d 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/ProfileRemoveDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/profile/ProfileRemoveDialog.kt @@ -2,7 +2,7 @@ * Copyright (c) Kuba Szczodrzyński 2019-11-13. */ -package pl.szczodrzynski.edziennik.ui.dialogs.settings +package pl.szczodrzynski.edziennik.ui.dialogs.profile import android.widget.Toast import androidx.appcompat.app.AlertDialog @@ -18,7 +18,8 @@ class ProfileRemoveDialog( val activity: MainActivity, val profileId: Int, val profileName: String, - val noProfileRemoval: Boolean = false + val noProfileRemoval: Boolean = false, + val onRemove: (() -> Unit)? = null ) : CoroutineScope { companion object { private const val TAG = "ProfileRemoveDialog" @@ -95,5 +96,6 @@ class ProfileRemoveDialog( dialog.dismiss() activity.reloadTarget() Toast.makeText(activity, R.string.dialog_profile_remove_success, Toast.LENGTH_LONG).show() + onRemove?.invoke() }} } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/RegistrationConfigDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/RegistrationConfigDialog.kt index 9470534d..fff65b43 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/RegistrationConfigDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/RegistrationConfigDialog.kt @@ -104,10 +104,12 @@ class RegistrationConfigDialog( // force full registration of the user App.config.getFor(profile.id).hash = "" - AppSync(app, mutableListOf(), listOf(profile), SzkolnyApi(app)).run( - 0L, - markAsSeen = true - ) + SzkolnyApi(app).runCatching(activity) { + AppSync(app, mutableListOf(), listOf(profile), this).run( + 0L, + markAsSeen = true + ) + } app.db.profileDao().add(profile) if (profile.id == App.profileId) { App.profile.registration = profile.registration diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/debug/LabPageFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/debug/LabPageFragment.kt index 29a0b2b3..b1b84f9d 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/debug/LabPageFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/debug/LabPageFragment.kt @@ -16,7 +16,7 @@ import kotlinx.coroutines.launch import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.db.entity.Event import pl.szczodrzynski.edziennik.databinding.LabFragmentBinding -import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog +import pl.szczodrzynski.edziennik.ui.dialogs.profile.ProfileRemoveDialog import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.LazyFragment import pl.szczodrzynski.edziennik.utils.TextInputDropDown import pl.szczodrzynski.fslogin.decode diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java index 80aee4dd..a3018097 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java @@ -54,8 +54,8 @@ import pl.szczodrzynski.edziennik.sync.SyncWorker; import pl.szczodrzynski.edziennik.sync.UpdateWorker; import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog; import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradesConfigDialog; +import pl.szczodrzynski.edziennik.ui.dialogs.profile.ProfileRemoveDialog; import pl.szczodrzynski.edziennik.ui.dialogs.settings.AttendanceConfigDialog; -import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog; import pl.szczodrzynski.edziennik.ui.dialogs.sync.NotificationFilterDialog; import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity; import pl.szczodrzynski.edziennik.utils.Themes; @@ -253,7 +253,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { icon(SzkolnyFont.Icon.szf_delete_empty_outline, iconSizeDp, iconColor) ) .setOnClickAction(() -> { - new ProfileRemoveDialog(activity, app.getProfile().getId(), app.getProfile().getName(), false); + new ProfileRemoveDialog(activity, app.getProfile().getId(), app.getProfile().getName(), false, null); }) ); diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsUtil.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsUtil.kt index 5ed3fb5d..258f4a17 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsUtil.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsUtil.kt @@ -4,8 +4,6 @@ package pl.szczodrzynski.edziennik.ui.modules.settings -import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory -import androidx.core.graphics.drawable.toBitmap import com.danielstone.materialaboutlibrary.items.* import com.danielstone.materialaboutlibrary.model.MaterialAboutCard import com.mikepenz.iconics.IconicsDrawable @@ -27,11 +25,12 @@ class SettingsUtil( fun refresh() = onRefresh() - private fun IIcon.asDrawable(color: Int? = null, size: Int = 20) = IconicsDrawable(activity).apply { - icon = this@asDrawable - sizeDp = size - colorInt = color ?: Themes.getPrimaryTextColor(activity) - } + private fun IIcon.asDrawable(color: Int? = null, size: Int = 20) = + IconicsDrawable(activity).apply { + icon = this@asDrawable + sizeDp = size + colorInt = color ?: Themes.getPrimaryTextColor(activity) + } fun createCard( titleRes: Int?, @@ -171,18 +170,20 @@ class SettingsUtil( .icon(R.mipmap.ic_splash) .build() - fun createProfileItem(profile: Profile, onClick: (profile: Profile) -> Unit) = - MaterialAboutProfileItem( + fun createProfileItem( + profile: Profile, + onClick: (item: MaterialAboutProfileItem, profile: Profile) -> Unit + ): MaterialAboutProfileItem { + val item = MaterialAboutProfileItem( MaterialAboutTitleItem.Builder() .text(profile.name) .desc(profile.subname) - .icon(RoundedBitmapDrawableFactory.create( - activity.resources, - profile.getImageDrawable(activity).toBitmap() - ).also { - it.isCircular = true - }) - .setOnClickAction { onClick(profile) } + .icon(profile.getImageDrawable(activity)) .build() ) + item.setOnClickAction { + onClick(item, profile) + } + return item + } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsProfileCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsProfileCard.kt index a783731f..5ac23e62 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsProfileCard.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsProfileCard.kt @@ -8,8 +8,10 @@ import android.content.Intent import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial import eu.szkolny.font.SzkolnyFont import pl.szczodrzynski.edziennik.R -import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog +import pl.szczodrzynski.edziennik.ui.dialogs.profile.ProfileConfigDialog +import pl.szczodrzynski.edziennik.ui.dialogs.profile.ProfileRemoveDialog import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity +import pl.szczodrzynski.edziennik.ui.modules.settings.MaterialAboutProfileItem import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsCard import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsUtil @@ -21,12 +23,21 @@ class SettingsProfileCard(util: SettingsUtil) : SettingsCard(util) { itemsMore = getItemsMore() ) - override fun getItems() = listOf( - util.createProfileItem( - profile = app.profile - ) { + private fun getProfileItem(): MaterialAboutProfileItem = util.createProfileItem( + profile = app.profile + ) { item, profile -> + ProfileConfigDialog(activity, profile, onProfileSaved = { + val index = card.items.indexOf(item) + if (index == -1) + return@ProfileConfigDialog + card.items.remove(item) + card.items.add(index, getProfileItem()) + util.refresh() + }) + } - }, + override fun getItems() = listOf( + getProfileItem(), util.createActionItem( text = R.string.settings_add_student_text, diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsThemeCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsThemeCard.kt index 0cb710cb..17b108e5 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsThemeCard.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsThemeCard.kt @@ -4,6 +4,7 @@ package pl.szczodrzynski.edziennik.ui.modules.settings.cards +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.ui.dialogs.settings.AppLanguageDialog @@ -74,7 +75,28 @@ class SettingsThemeCard(util: SettingsUtil) : SettingsCard(util) { text = R.string.settings_theme_drawer_header_text, icon = CommunityMaterial.Icon2.cmd_image_outline ) { - // TODO: 2021-03-17 + if (app.config.ui.appBackground == null) { + setHeaderBackground() + return@createActionItem + } + MaterialAlertDialogBuilder(activity) + .setItems( + arrayOf( + activity.getString(R.string.settings_theme_drawer_header_dialog_set), + activity.getString(R.string.settings_theme_drawer_header_dialog_restore) + ) + ) { _, which -> + when (which) { + 0 -> setHeaderBackground() + 1 -> { + app.config.ui.headerBackground = null + activity.drawer.setAccountHeaderBackground(null) + activity.drawer.open() + } + } + } + .setNegativeButton(R.string.cancel, null) + .show() }, util.createActionItem( @@ -82,7 +104,27 @@ class SettingsThemeCard(util: SettingsUtil) : SettingsCard(util) { subText = R.string.settings_theme_app_background_subtext, icon = CommunityMaterial.Icon2.cmd_image_filter_hdr ) { - // TODO: 2021-03-17 + if (app.config.ui.appBackground == null) { + setAppBackground() + return@createActionItem + } + MaterialAlertDialogBuilder(activity) + .setItems( + arrayOf( + activity.getString(R.string.settings_theme_app_background_dialog_set), + activity.getString(R.string.settings_theme_app_background_dialog_restore) + ) + ) { _, which -> + when (which) { + 0 -> setAppBackground() + 1 -> { + app.config.ui.appBackground = null + activity.setAppBackground() + } + } + } + .setNegativeButton(R.string.cancel, null) + .show() }, util.createPropertyItem( @@ -93,4 +135,14 @@ class SettingsThemeCard(util: SettingsUtil) : SettingsCard(util) { configGlobal.ui.openDrawerOnBackPressed = it } ) + + private fun setHeaderBackground() = activity.requestHandler.requestHeaderBackground { + activity.drawer.setAccountHeaderBackground(null) + activity.drawer.setAccountHeaderBackground(app.config.ui.headerBackground) + activity.drawer.open() + } + + private fun setAppBackground() = activity.requestHandler.requestAppBackground { + activity.setAppBackground() + } } diff --git a/app/src/main/res/layout/dialog_profile_config.xml b/app/src/main/res/layout/dialog_profile_config.xml new file mode 100644 index 00000000..e83af680 --- /dev/null +++ b/app/src/main/res/layout/dialog_profile_config.xml @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/mal_material_about_profile_item.xml b/app/src/main/res/layout/mal_material_about_profile_item.xml index e1802130..4b94b21e 100644 --- a/app/src/main/res/layout/mal_material_about_profile_item.xml +++ b/app/src/main/res/layout/mal_material_about_profile_item.xml @@ -6,7 +6,7 @@ android:orientation="horizontal" android:paddingHorizontal="@dimen/mal_baseline_half"> - Uzyskaj pomoc lub wesprzyj autorów Kod źródłowy Pomóż w rozwoju aplikacji na GitHubie + Nazwa profilu + Synchronizuj ten profil + Wyloguj się From 549a5428799a66ff11bd70f475ca48b23ad4a5bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 25 Mar 2021 16:36:38 +0100 Subject: [PATCH 036/113] [UI/Settings] Fix picking images from camera app. --- app/build.gradle | 2 +- app/src/main/AndroidManifest.xml | 2 +- .../edziennik/MainActivityRequestHandler.kt | 9 ++++++--- .../ui/modules/settings/SettingsNewFragment.java | 4 ++-- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 15d7cdff..8586b655 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -139,6 +139,7 @@ dependencies { implementation "com.daimajia.swipelayout:library:1.2.0@aar" implementation "com.github.antonKozyriatskyi:CircularProgressIndicator:1.2.2" implementation "com.github.bassaer:chatmessageview:2.0.1" + implementation "com.github.CanHub:Android-Image-Cropper:2.2.2" implementation "com.github.ChuckerTeam.Chucker:library:3.0.1" implementation "com.github.jetradarmobile:android-snowfall:1.2.0" implementation "com.github.wulkanowy.uonet-request-signer:hebe-jvm:a99ca50a31" @@ -147,7 +148,6 @@ dependencies { implementation "com.jaredrummler:colorpicker:1.1.0" implementation "com.qifan.powerpermission:powerpermission-coroutines:1.3.0" implementation "com.qifan.powerpermission:powerpermission:1.3.0" - implementation "com.theartofdev.edmodo:android-image-cropper:2.8.0" implementation "com.wdullaer:materialdatetimepicker:4.2.3" implementation "com.yuyh.json:jsonviewer:1.0.6" implementation "io.coil-kt:coil:1.1.1" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6e8fc491..39704c99 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -144,7 +144,7 @@ android:configChanges="orientation|keyboardHidden" android:theme="@style/AppTheme" /> - diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivityRequestHandler.kt b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivityRequestHandler.kt index 3f086a44..a54641b8 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivityRequestHandler.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivityRequestHandler.kt @@ -8,8 +8,8 @@ import android.app.Activity import android.content.Intent import android.net.Uri import android.provider.OpenableColumns -import com.theartofdev.edmodo.cropper.CropImage -import com.theartofdev.edmodo.cropper.CropImageView +import com.canhub.cropper.CropImage +import com.canhub.cropper.CropImageView import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity import java.io.File @@ -76,6 +76,9 @@ class MainActivityRequestHandler(val activity: MainActivity) { } private fun getFileInfo(uri: Uri): Pair { + if (uri.scheme == "file") { + return (uri.lastPathSegment ?: "unknown") to null + } val cursor = activity.contentResolver.query( uri, null, @@ -118,7 +121,7 @@ class MainActivityRequestHandler(val activity: MainActivity) { fun handleResult(requestCode: Int, resultCode: Int, data: Intent?) { if (resultCode != Activity.RESULT_OK) return - var uri = data?.data + var uri = CropImage.getPickImageResultUri(activity, data) when (requestCode) { REQUEST_LOGIN_ACTIVITY -> { if (!app.config.loginFinished) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java index a3018097..c9a550bd 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java @@ -15,6 +15,8 @@ import android.provider.Settings; import android.widget.Toast; import com.afollestad.materialdialogs.MaterialDialog; +import com.canhub.cropper.CropImage; +import com.canhub.cropper.CropImageView; import com.danielstone.materialaboutlibrary.ConvenienceBuilder; import com.danielstone.materialaboutlibrary.MaterialAboutFragment; import com.danielstone.materialaboutlibrary.items.MaterialAboutActionItem; @@ -30,8 +32,6 @@ import com.mikepenz.iconics.typeface.IIcon; import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial; import com.mikepenz.iconics.utils.IconicsConvertersKt; import com.mikepenz.iconics.utils.IconicsDrawableExtensionsKt; -import com.theartofdev.edmodo.cropper.CropImage; -import com.theartofdev.edmodo.cropper.CropImageView; import com.wdullaer.materialdatetimepicker.time.TimePickerDialog; import java.io.File; From 7a43ef4dee98839abc63d63136fdc486439c4742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 25 Mar 2021 16:45:14 +0100 Subject: [PATCH 037/113] [App] Remove unneeded profile settings. --- .../ui/modules/settings/SettingsCard.kt | 2 +- .../settings/cards/SettingsProfileCard.kt | 24 +------------------ 2 files changed, 2 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsCard.kt index c31116d9..36ce3777 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsCard.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsCard.kt @@ -24,5 +24,5 @@ abstract class SettingsCard( protected abstract fun buildCard(): MaterialAboutCard protected abstract fun getItems(): List - protected abstract fun getItemsMore(): List + protected open fun getItemsMore(): List = listOf() } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsProfileCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsProfileCard.kt index 5ac23e62..f88a0242 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsProfileCard.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsProfileCard.kt @@ -6,10 +6,8 @@ package pl.szczodrzynski.edziennik.ui.modules.settings.cards import android.content.Intent import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial -import eu.szkolny.font.SzkolnyFont import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.ui.dialogs.profile.ProfileConfigDialog -import pl.szczodrzynski.edziennik.ui.dialogs.profile.ProfileRemoveDialog import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity import pl.szczodrzynski.edziennik.ui.modules.settings.MaterialAboutProfileItem import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsCard @@ -20,7 +18,7 @@ class SettingsProfileCard(util: SettingsUtil) : SettingsCard(util) { override fun buildCard() = util.createCard( null, items = getItems(), - itemsMore = getItemsMore() + itemsMore = listOf() ) private fun getProfileItem(): MaterialAboutProfileItem = util.createProfileItem( @@ -45,26 +43,6 @@ class SettingsProfileCard(util: SettingsUtil) : SettingsCard(util) { icon = CommunityMaterial.Icon.cmd_account_plus_outline ) { activity.startActivity(Intent(activity, LoginActivity::class.java)) - }, - - util.createActionItem( - text = R.string.settings_profile_remove_text, - subText = R.string.settings_profile_remove_subtext, - icon = SzkolnyFont.Icon.szf_delete_empty_outline - ) { - ProfileRemoveDialog(activity, app.profile.id, app.profile.name, false) - } - ) - - override fun getItemsMore() = listOf( - util.createPropertyItem( - text = R.string.settings_profile_sync_text, - subText = R.string.settings_profile_sync_subtext, - icon = CommunityMaterial.Icon.cmd_account_convert, - value = app.profile.syncEnabled, - ) { _, it -> - app.profile.syncEnabled = it - app.profileSave() } ) } From a5cbee2b45b6f45743406a65eac7091bdfc7b03d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 25 Mar 2021 17:29:43 +0100 Subject: [PATCH 038/113] [UI/Settings] Fix profile image button icon background. --- .../ui/dialogs/profile/ProfileConfigDialog.kt | 12 ++++++++++++ app/src/main/res/layout/dialog_profile_config.xml | 12 +++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/profile/ProfileConfigDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/profile/ProfileConfigDialog.kt index 6d51d3a1..dbfdd4e4 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/profile/ProfileConfigDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/profile/ProfileConfigDialog.kt @@ -4,9 +4,12 @@ package pl.szczodrzynski.edziennik.ui.dialogs.profile +import android.content.res.ColorStateList import androidx.appcompat.app.AlertDialog import androidx.core.widget.addTextChangedListener +import com.google.android.material.color.MaterialColors import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.google.android.material.shape.MaterialShapeDrawable import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job @@ -59,6 +62,15 @@ class ProfileConfigDialog( b.profile = profile profile.applyImageTo(b.image) + // I can't believe how simple it is to get the dialog's background color !! + val shape = MaterialShapeDrawable(activity, null, R.attr.alertDialogStyle, R.style.MaterialAlertDialog_MaterialComponents) + val surface = MaterialColors.getColor(activity, R.attr.colorSurface, TAG) + shape.setCornerSize(18.dp.toFloat()) + shape.initializeElevationOverlay(activity) + shape.fillColor = ColorStateList.valueOf(surface) + shape.elevation = 16.dp.toFloat() + b.circleView.background = shape + b.nameEdit.addTextChangedListener { profileChanged = true } diff --git a/app/src/main/res/layout/dialog_profile_config.xml b/app/src/main/res/layout/dialog_profile_config.xml index e83af680..ecba48da 100644 --- a/app/src/main/res/layout/dialog_profile_config.xml +++ b/app/src/main/res/layout/dialog_profile_config.xml @@ -39,16 +39,22 @@ android:scaleType="centerCrop" tools:src="@drawable/face_1" /> + + + app:iiv_padding="5dp" + tools:background="@color/colorSurface_16dp" /> Date: Thu, 25 Mar 2021 17:43:43 +0100 Subject: [PATCH 039/113] [UI/Settings] Add requesting camera permissions to pick image. --- .../edziennik/MainActivityRequestHandler.kt | 92 ++++++++++-------- .../utils/managers/PermissionManager.kt | 96 +++++++++++++------ 2 files changed, 121 insertions(+), 67 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivityRequestHandler.kt b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivityRequestHandler.kt index a54641b8..a39a5872 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivityRequestHandler.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivityRequestHandler.kt @@ -30,50 +30,62 @@ class MainActivityRequestHandler(val activity: MainActivity) { private val requestData = mutableMapOf() private val listeners = mutableMapOf Unit>() + private val manager + get() = app.permissionManager + fun requestLogin() = activity.startActivityForResult( Intent(activity, LoginActivity::class.java), REQUEST_LOGIN_ACTIVITY ) - fun requestHeaderBackground(listener: (Any?) -> Unit) { - listeners[REQUEST_FILE_HEADER_BACKGROUND] = listener - activity.startActivityForResult( - CropImage.getPickImageChooserIntent( - activity, - activity.getString(R.string.pick_image_intent_chooser_title), - true, - true - ), - REQUEST_FILE_HEADER_BACKGROUND - ) - } + fun requestHeaderBackground(listener: (Any?) -> Unit) = + manager.requestCameraPermission( + activity, 0, isRequired = false + ) { + listeners[REQUEST_FILE_HEADER_BACKGROUND] = listener + activity.startActivityForResult( + CropImage.getPickImageChooserIntent( + activity, + activity.getString(R.string.pick_image_intent_chooser_title), + true, + true + ), + REQUEST_FILE_HEADER_BACKGROUND + ) + } - fun requestAppBackground(listener: (Any?) -> Unit) { - listeners[REQUEST_FILE_APP_BACKGROUND] = listener - activity.startActivityForResult( - CropImage.getPickImageChooserIntent( - activity, - activity.getString(R.string.pick_image_intent_chooser_title), - true, - true - ), - REQUEST_FILE_APP_BACKGROUND - ) - } + fun requestAppBackground(listener: (Any?) -> Unit) = + manager.requestCameraPermission( + activity, 0, isRequired = false + ) { + listeners[REQUEST_FILE_APP_BACKGROUND] = listener + activity.startActivityForResult( + CropImage.getPickImageChooserIntent( + activity, + activity.getString(R.string.pick_image_intent_chooser_title), + true, + true + ), + REQUEST_FILE_APP_BACKGROUND + ) + } - fun requestProfileImage(profile: Profile, listener: (Any?) -> Unit) { - listeners[REQUEST_FILE_PROFILE_IMAGE] = listener - requestData[REQUEST_FILE_PROFILE_IMAGE] = profile - activity.startActivityForResult( - CropImage.getPickImageChooserIntent( - activity, - activity.getString(R.string.pick_image_intent_chooser_title), - true, - true - ), - REQUEST_FILE_PROFILE_IMAGE - ) - } + fun requestProfileImage(profile: Profile, listener: (Any?) -> Unit) = + manager.requestCameraPermission( + activity, 0, isRequired = false + ) { + listeners[REQUEST_FILE_PROFILE_IMAGE] = listener + requestData[REQUEST_FILE_PROFILE_IMAGE] = profile + activity.startActivityForResult( + CropImage.getPickImageChooserIntent( + activity, + activity.getString(R.string.pick_image_intent_chooser_title), + true, + true + ), + REQUEST_FILE_PROFILE_IMAGE + ) + } private fun getFileInfo(uri: Uri): Pair { if (uri.scheme == "file") { @@ -95,8 +107,7 @@ class MainActivityRequestHandler(val activity: MainActivity) { val mimeType = if (mimeIndex != -1) it.getString(mimeIndex) else null name to mimeType - } - else + } else null } ?: "unknown" to null } @@ -178,7 +189,8 @@ class MainActivityRequestHandler(val activity: MainActivity) { .getIntent(activity) activity.startActivityForResult(intent, REQUEST_CROP_PROFILE_IMAGE) } else { - val profile = requestData.remove(REQUEST_FILE_PROFILE_IMAGE) as? Profile ?: return + val profile = + requestData.remove(REQUEST_FILE_PROFILE_IMAGE) as? Profile ?: return val path = saveFile(uri, "profile${profile.id}") profile.image = path listeners.remove(REQUEST_FILE_PROFILE_IMAGE)?.invoke(profile) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/PermissionManager.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/PermissionManager.kt index 4b80f44b..65430f60 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/PermissionManager.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/PermissionManager.kt @@ -31,49 +31,91 @@ class PermissionManager(val app: App) : CoroutineScope { override val coroutineContext: CoroutineContext get() = job + Dispatchers.Main - private fun isStoragePermissionGranted() = if (Build.VERSION.SDK_INT >= 23) { - app.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED - } else { - true + private fun isPermissionGranted(name: String) = + if (Build.VERSION.SDK_INT >= 23) + app.checkSelfPermission(name) == PackageManager.PERMISSION_GRANTED + else + true + + private fun openPermissionSettings(activity: AppCompatActivity) { + val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) + val uri = Uri.fromParts("package", app.packageName, null) + intent.data = uri + activity.startActivity(intent) } - fun requestStoragePermission( - activity: AppCompatActivity, - @StringRes permissionMessage: Int, - onSuccess: suspend CoroutineScope.() -> Unit + private fun requestPermission( + activity: AppCompatActivity, + @StringRes permissionMessage: Int, + isRequired: Boolean = true, + permissionName: String, + onSuccess: suspend CoroutineScope.() -> Unit ) { launch { - if (isStoragePermissionGranted()) { + if (isPermissionGranted(permissionName)) { onSuccess() return@launch } - val result = activity.awaitAskPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE) + val result = activity.awaitAskPermissions(permissionName) when { result.hasAllGranted() -> onSuccess() result.hasRational() -> { + if (!isRequired) { + onSuccess() + return@launch + } MaterialAlertDialogBuilder(activity) - .setTitle(R.string.permissions_required) - .setMessage(permissionMessage) - .setPositiveButton(R.string.ok) { _, _ -> - requestStoragePermission(activity, permissionMessage, onSuccess) - } - .setNegativeButton(R.string.cancel, null) - .show() + .setTitle(R.string.permissions_required) + .setMessage(permissionMessage) + .setPositiveButton(R.string.ok) { _, _ -> + requestPermission( + activity, + permissionMessage, + isRequired, + permissionName, + onSuccess + ) + } + .setNegativeButton(R.string.cancel, null) + .show() } result.hasPermanentDenied() -> { MaterialAlertDialogBuilder(activity) - .setTitle(R.string.permissions_required) - .setMessage(R.string.permissions_denied) - .setPositiveButton(R.string.ok) { _, _ -> - val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) - val uri = Uri.fromParts("package", app.packageName, null) - intent.data = uri - activity.startActivity(intent) - } - .setNegativeButton(R.string.cancel, null) - .show() + .setTitle(R.string.permissions_required) + .setMessage(R.string.permissions_denied) + .setPositiveButton(R.string.ok) { _, _ -> + openPermissionSettings(activity) + } + .setNegativeButton(R.string.cancel, null) + .show() } } } } + + fun requestStoragePermission( + activity: AppCompatActivity, + @StringRes permissionMessage: Int, + isRequired: Boolean = true, + onSuccess: suspend CoroutineScope.() -> Unit + ) = requestPermission( + activity, + permissionMessage, + isRequired, + Manifest.permission.WRITE_EXTERNAL_STORAGE, + onSuccess + ) + + fun requestCameraPermission( + activity: AppCompatActivity, + @StringRes permissionMessage: Int, + isRequired: Boolean = true, + onSuccess: suspend CoroutineScope.() -> Unit + ) = requestPermission( + activity, + permissionMessage, + isRequired, + Manifest.permission.CAMERA, + onSuccess + ) } From d9b91d6de8b2ef38f01f209cf931e210ec2e35af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 25 Mar 2021 17:47:02 +0100 Subject: [PATCH 040/113] [UI/Settings] Add requesting camera permissions in web push fragment. --- .../ui/modules/webpush/WebPushFragment.kt | 19 +++++-------------- app/src/main/res/values/strings.xml | 1 + 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/webpush/WebPushFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/webpush/WebPushFragment.kt index 4c8c34cc..0996c518 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/webpush/WebPushFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/webpush/WebPushFragment.kt @@ -4,15 +4,11 @@ package pl.szczodrzynski.edziennik.ui.modules.webpush -import android.Manifest import android.annotation.SuppressLint -import android.content.pm.PackageManager import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.core.app.ActivityCompat -import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import androidx.recyclerview.widget.LinearLayoutManager import kotlinx.coroutines.CoroutineScope @@ -25,7 +21,6 @@ import pl.szczodrzynski.edziennik.data.api.szkolny.response.WebPushResponse import pl.szczodrzynski.edziennik.databinding.WebPushFragmentBinding import pl.szczodrzynski.edziennik.ui.dialogs.QrScannerDialog import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration -import pl.szczodrzynski.edziennik.utils.Themes import kotlin.coroutines.CoroutineContext class WebPushFragment : Fragment(), CoroutineScope { @@ -46,13 +41,13 @@ class WebPushFragment : Fragment(), CoroutineScope { SzkolnyApi(app) } + private val manager + get() = app.permissionManager + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { activity = (getActivity() as MainActivity?) ?: return null context ?: return null app = activity.application as App - context!!.theme.applyStyle(Themes.appTheme, true) - if (app.profile == null) - return inflater.inflate(R.layout.fragment_loading, container, false) // activity, context and profile is valid b = WebPushFragmentBinding.inflate(inflater) return b.root @@ -60,19 +55,15 @@ class WebPushFragment : Fragment(), CoroutineScope { @SuppressLint("DefaultLocale") override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - // TODO check if app, activity, b can be null - if (app.profile == null || !isAdded) + if (!isAdded) return b.scanQrCode.onClick { - val result = ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA) - if (result == PackageManager.PERMISSION_GRANTED) { + manager.requestCameraPermission(activity, R.string.permissions_qr_scanner) { QrScannerDialog(activity, { b.tokenEditText.setText(it.crc32().toString(36).toUpperCase()) pairBrowser(browserId = it) }) - } else { - ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.CAMERA), 1) } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f4dfd1fc..a5f8621f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1398,4 +1398,5 @@ Nazwa profilu Synchronizuj ten profil Wyloguj się + Aby móc zeskanować kod QR musisz przyznać uprawnienia dostępu do kamery.\n\nKliknij OK, aby przyznać uprawnienia. From df4b6ec3e5ee50602e2b510269cf5b91a5f352a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 25 Mar 2021 17:51:25 +0100 Subject: [PATCH 041/113] [UI/Profile] Fix new profile image not showing. --- .../edziennik/ui/dialogs/profile/ProfileConfigDialog.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/profile/ProfileConfigDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/profile/ProfileConfigDialog.kt index dbfdd4e4..e9204090 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/profile/ProfileConfigDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/profile/ProfileConfigDialog.kt @@ -85,7 +85,7 @@ class ProfileConfigDialog( if (this@ProfileConfigDialog.profile == profile) { profileChanged = true b.profile = profile - profile.applyImageTo(b.image) + b.image.setImageDrawable(profile.getImageDrawable(activity)) } } } From 6e9a0b217d5f711cb1a75a9e9ac3b502d8860206 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 25 Mar 2021 17:57:05 +0100 Subject: [PATCH 042/113] [UI] Remove unused permission checking. --- app/src/main/AndroidManifest.xml | 1 - .../pl/szczodrzynski/edziennik/Extensions.kt | 17 ----- .../ui/modules/webpush/QrScannerActivity.java | 75 ------------------- 3 files changed, 93 deletions(-) delete mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/webpush/QrScannerActivity.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 39704c99..15919246 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -143,7 +143,6 @@ - diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt index aaf0eec7..c17f4b3a 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt @@ -1,12 +1,9 @@ package pl.szczodrzynski.edziennik -import android.Manifest -import android.app.Activity import android.content.ClipData import android.content.ClipboardManager import android.content.Context import android.content.Intent -import android.content.pm.PackageManager import android.content.res.ColorStateList import android.content.res.Resources import android.database.Cursor @@ -29,7 +26,6 @@ import android.view.View import android.view.WindowManager import android.widget.* import androidx.annotation.* -import androidx.core.app.ActivityCompat import androidx.core.database.getIntOrNull import androidx.core.database.getLongOrNull import androidx.core.database.getStringOrNull @@ -304,19 +300,6 @@ fun colorFromCssName(name: String): Int { fun List.filterOutArchived() = this.filter { !it.archived } -fun Activity.isStoragePermissionGranted(): Boolean { - return if (Build.VERSION.SDK_INT >= 23) { - if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { - true - } else { - ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 1) - false - } - } else { - true - } -} - fun Response?.getUnixDate(): Long { val rfcDate = this?.headers()?.get("date") ?: return currentTimeUnix() val pattern = "EEE, dd MMM yyyy HH:mm:ss Z" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/webpush/QrScannerActivity.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/webpush/QrScannerActivity.java deleted file mode 100644 index b9028ac5..00000000 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/webpush/QrScannerActivity.java +++ /dev/null @@ -1,75 +0,0 @@ -package pl.szczodrzynski.edziennik.ui.modules.webpush; - -import android.Manifest; -import android.content.pm.PackageManager; -import android.os.Bundle; -import android.widget.Toast; - -import androidx.annotation.NonNull; -import androidx.appcompat.app.AppCompatActivity; -import androidx.core.app.ActivityCompat; -import androidx.core.content.ContextCompat; - -import com.google.zxing.Result; - -import me.dm7.barcodescanner.zxing.ZXingScannerView; -import pl.szczodrzynski.edziennik.R; - -public class QrScannerActivity extends AppCompatActivity implements ZXingScannerView.ResultHandler { - private ZXingScannerView mScannerView; - public static ZXingScannerView.ResultHandler resultHandler; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mScannerView = new ZXingScannerView(this); // Programmatically initialize the scanner view - setContentView(mScannerView); - int result = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA); - if (result == PackageManager.PERMISSION_GRANTED) { - mScannerView.setResultHandler(this); // Register ourselves as a handler for scan results. - mScannerView.startCamera(); // Start camera on resume - } else { - ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 1); - } - } - - @Override - public void onResume() { - super.onResume(); - mScannerView.setResultHandler(this); // Register ourselves as a handler for scan results. - mScannerView.startCamera(); // Start camera on resume - } - - @Override - public void onPause() { - super.onPause(); - mScannerView.stopCamera(); // Stop camera on pause - } - - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - switch (requestCode) { - case 1: { - // If request is cancelled, the result arrays are empty. - if (grantResults.length > 0 - && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - mScannerView.startCamera(); - } else { - // permission denied, boo! Disable the - // functionality that depends on this permission. - Toast.makeText(this, R.string.no_permissions, Toast.LENGTH_SHORT).show(); - } - } - // other 'case' lines to check for other - // permissions this app might request - } - } - - @Override - public void handleResult(Result rawResult) { - if (resultHandler != null) { - resultHandler.handleResult(rawResult); - } - finish(); - } -} From d191982da63811a075688d6930dbc9ca354d279f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 25 Mar 2021 17:59:31 +0100 Subject: [PATCH 043/113] [UI] Remove old SettingsNewFragment. --- .../szczodrzynski/edziennik/MainActivity.kt | 7 - .../modules/settings/SettingsNewFragment.java | 1292 ----------------- 2 files changed, 1299 deletions(-) delete mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt index 971a46d2..f4b8cafa 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt @@ -79,7 +79,6 @@ import pl.szczodrzynski.edziennik.ui.modules.messages.compose.MessagesComposeFra import pl.szczodrzynski.edziennik.ui.modules.notifications.NotificationsListFragment import pl.szczodrzynski.edziennik.ui.modules.settings.ProfileManagerFragment import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsFragment -import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsNewFragment import pl.szczodrzynski.edziennik.ui.modules.timetable.TimetableFragment import pl.szczodrzynski.edziennik.ui.modules.webpush.WebPushFragment import pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoTouch @@ -202,12 +201,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope { .isStatic(true) .isBelowSeparator(true) - list += NavTarget(DRAWER_ITEM_SETTINGS+1, R.string.menu_settings, SettingsNewFragment::class) - .withIcon(CommunityMaterial.Icon3.cmd_seal) - .isInDrawer(true) - .isStatic(true) - .isBelowSeparator(true) - // profile settings items list += NavTarget(DRAWER_PROFILE_ADD_NEW, R.string.menu_add_new_profile, null) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java deleted file mode 100644 index c9a550bd..00000000 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java +++ /dev/null @@ -1,1292 +0,0 @@ -package pl.szczodrzynski.edziennik.ui.modules.settings; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Color; -import android.graphics.drawable.Drawable; -import android.media.MediaPlayer; -import android.net.Uri; -import android.os.AsyncTask; -import android.os.Build; -import android.provider.Settings; -import android.widget.Toast; - -import com.afollestad.materialdialogs.MaterialDialog; -import com.canhub.cropper.CropImage; -import com.canhub.cropper.CropImageView; -import com.danielstone.materialaboutlibrary.ConvenienceBuilder; -import com.danielstone.materialaboutlibrary.MaterialAboutFragment; -import com.danielstone.materialaboutlibrary.items.MaterialAboutActionItem; -import com.danielstone.materialaboutlibrary.items.MaterialAboutActionSwitchItem; -import com.danielstone.materialaboutlibrary.items.MaterialAboutItem; -import com.danielstone.materialaboutlibrary.items.MaterialAboutItemOnClickAction; -import com.danielstone.materialaboutlibrary.items.MaterialAboutSwitchItem; -import com.danielstone.materialaboutlibrary.items.MaterialAboutTitleItem; -import com.danielstone.materialaboutlibrary.model.MaterialAboutCard; -import com.danielstone.materialaboutlibrary.model.MaterialAboutList; -import com.mikepenz.iconics.IconicsDrawable; -import com.mikepenz.iconics.typeface.IIcon; -import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial; -import com.mikepenz.iconics.utils.IconicsConvertersKt; -import com.mikepenz.iconics.utils.IconicsDrawableExtensionsKt; -import com.wdullaer.materialdatetimepicker.time.TimePickerDialog; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import eu.szkolny.font.SzkolnyFont; -import kotlin.Unit; -import pl.szczodrzynski.edziennik.App; -import pl.szczodrzynski.edziennik.BuildConfig; -import pl.szczodrzynski.edziennik.ExtensionsKt; -import pl.szczodrzynski.edziennik.MainActivity; -import pl.szczodrzynski.edziennik.R; -import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi; -import pl.szczodrzynski.edziennik.data.db.entity.LoginStore; -import pl.szczodrzynski.edziennik.network.NetworkUtils; -import pl.szczodrzynski.edziennik.sync.SyncWorker; -import pl.szczodrzynski.edziennik.sync.UpdateWorker; -import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog; -import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradesConfigDialog; -import pl.szczodrzynski.edziennik.ui.dialogs.profile.ProfileRemoveDialog; -import pl.szczodrzynski.edziennik.ui.dialogs.settings.AttendanceConfigDialog; -import pl.szczodrzynski.edziennik.ui.dialogs.sync.NotificationFilterDialog; -import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity; -import pl.szczodrzynski.edziennik.utils.Themes; -import pl.szczodrzynski.edziennik.utils.Utils; -import pl.szczodrzynski.edziennik.utils.models.Date; -import pl.szczodrzynski.edziennik.utils.models.Time; - -import static android.app.Activity.RESULT_OK; -import static pl.szczodrzynski.edziennik.ExtensionsKt.initDefaultLocale; -import static pl.szczodrzynski.edziennik.data.db.entity.Profile.REGISTRATION_DISABLED; -import static pl.szczodrzynski.edziennik.data.db.entity.Profile.REGISTRATION_ENABLED; -import static pl.szczodrzynski.edziennik.utils.Utils.d; -import static pl.szczodrzynski.edziennik.utils.Utils.getRealPathFromURI; -import static pl.szczodrzynski.edziennik.utils.Utils.getResizedBitmap; -import static pl.szczodrzynski.edziennik.utils.managers.GradesManager.YEAR_1_AVG_2_AVG; -import static pl.szczodrzynski.edziennik.utils.managers.GradesManager.YEAR_1_AVG_2_SEM; -import static pl.szczodrzynski.edziennik.utils.managers.GradesManager.YEAR_1_SEM_2_AVG; -import static pl.szczodrzynski.edziennik.utils.managers.GradesManager.YEAR_1_SEM_2_SEM; -import static pl.szczodrzynski.edziennik.utils.managers.GradesManager.YEAR_ALL_GRADES; - -public class SettingsNewFragment extends MaterialAboutFragment { - - private static final String TAG = "Settings"; - private App app = null; - private MainActivity activity; - - private static final int CARD_PROFILE = 0; - private static final int CARD_THEME = 1; - private static final int CARD_SYNC = 2; - private static final int CARD_REGISTER = 3; - private static final int CARD_ABOUT = 4; - private int iconColor = Color.WHITE; - private int primaryTextOnPrimaryBg = -1; - private int secondaryTextOnPrimaryBg = -1; - private int iconSizeDp = 20; - - private IconicsDrawable icon(IIcon icon, int sizeDp, int color) { - return new IconicsDrawable(activity).apply((drawable) -> { - drawable.setIcon(icon); - IconicsConvertersKt.setSizeDp(drawable, sizeDp); - IconicsDrawableExtensionsKt.setColorInt(drawable, color); - return Unit.INSTANCE; - }); - } - - private MaterialAboutCard getCardWithItems(CharSequence title, ArrayList items, boolean primaryColor) { - MaterialAboutCard card = new MaterialAboutCard.Builder().title(title).cardColor(0xff1976D2).build(); - card.getItems().addAll(items); - return card; - } - private MaterialAboutCard getCardWithItems(CharSequence title, ArrayList items) { - MaterialAboutCard card = new MaterialAboutCard.Builder().title(title).cardColor(Utils.getAttr(activity, R.attr.mal_card_background)).build(); - card.getItems().addAll(items); - return card; - } - private void addCardItems(int cardIndex, ArrayList itemsNew) { - ArrayList items = getList().getCards().get(cardIndex).getItems(); - items.remove(items.size() - 1); - items.addAll(itemsNew); - refreshMaterialAboutList(); - } - private void addCardItem(int cardIndex, int itemIndex, MaterialAboutItem item) { - ArrayList items = getList().getCards().get(cardIndex).getItems(); - items.add(itemIndex, item); - refreshMaterialAboutList(); - } - private void removeCardItem(int cardIndex, int itemIndex) { - ArrayList items = getList().getCards().get(cardIndex).getItems(); - items.remove(itemIndex); - refreshMaterialAboutList(); - } - private MaterialAboutActionItem getMoreItem(MaterialAboutItemOnClickAction onClickAction) { - return new MaterialAboutActionItem( - getString(R.string.settings_more_text), - null, - icon(CommunityMaterial.Icon.cmd_chevron_down, 14, iconColor), - onClickAction - ); - } - - - /* _____ __ _ _ - | __ \ / _(_) | - | |__) | __ ___ | |_ _| | ___ - | ___/ '__/ _ \| _| | |/ _ \ - | | | | | (_) | | | | | __/ - |_| |_| \___/|_| |_|_|\__*/ - private Drawable getProfileDrawable() { - return app.getProfile().getImageDrawable(activity); - - /*Bitmap profileImage = null; - if (app.getProfile().getImage() != null && !app.getProfile().getImage().equals("")) { - profileImage = BitmapFactory.decodeFile(app.getProfile().getImage()); - RoundedBitmapDrawable roundDrawable = RoundedBitmapDrawableFactory.create(getResources(), profileImage); - roundDrawable.setCircular(true); - return roundDrawable; - } - return getDrawableFromRes(getContext(), R.drawable.profile);*/ - - /*if (profileImage == null) { - profileImage = BitmapFactory.decodeResource(getResources(), R.drawable.profile); - } - profileImage = ThumbnailUtils.extractThumbnail(profileImage, Math.min(profileImage.getWidth(), profileImage.getHeight()), Math.min(profileImage.getWidth(), profileImage.getHeight())); - RoundedBitmapDrawable roundDrawable = RoundedBitmapDrawableFactory.create(getResources(), profileImage); - roundDrawable.setCircular(true); - return roundDrawable;*/ - } - private MaterialAboutTitleItem profileCardTitleItem; - private ArrayList getProfileCard(boolean expandedOnly) { - ArrayList items = new ArrayList<>(); - if (!expandedOnly) { - - profileCardTitleItem = new MaterialAboutTitleItem( - app.getProfile().getName(), - app.getProfile().getSubname(), - getProfileDrawable() - ); - profileCardTitleItem.setOnClickAction(() -> { - new MaterialDialog.Builder(activity) - .title(R.string.settings_profile_change_title) - .items( - getString(R.string.settings_profile_change_name), - getString(R.string.settings_profile_change_image), - app.getProfile().getImage() == null ? null : getString(R.string.settings_profile_remove_image) - ) - .itemsCallback((dialog, itemView, position, text) -> { - switch (position) { - case 0: - new MaterialDialog.Builder(activity) - .title(getString(R.string.settings_profile_change_name_dialog_title)) - .input(getString(R.string.settings_profile_change_name_dialog_text), app.getProfile().getName(), (dialog1, input) -> { - app.getProfile().setName(input.toString()); - profileCardTitleItem.setText(input); - profileCardTitleItem.setIcon(getProfileDrawable()); - refreshMaterialAboutList(); - app.profileSave(); - }) - .positiveText(R.string.ok) - .negativeText(R.string.cancel) - .show(); - break; - case 1: - startActivityForResult(CropImage.getPickImageChooserIntent(activity), 21); - break; - case 2: - app.getProfile().setImage(null); - profileCardTitleItem.setIcon(getProfileDrawable()); - refreshMaterialAboutList(); - app.profileSave(); - break; - } - }) - .negativeText(R.string.cancel) - .show(); - }); - items.add(profileCardTitleItem); - - /*items.add( - new MaterialAboutActionItem( - getString(R.string.settings_profile_change_password_text), - getString(R.string.settings_profile_change_password_subtext), - icon(CommunityMaterial.Icon2.cmd_key_variant, iconSizeDp, iconColor) - ) - .setOnClickAction(() -> { - - }) - );*/ - - items.add( - new MaterialAboutActionItem( - getString(R.string.settings_add_student_text), - getString(R.string.settings_add_student_subtext), - icon(CommunityMaterial.Icon.cmd_account_plus_outline, iconSizeDp, iconColor) - ) - .setOnClickAction(() -> { - startActivity(new Intent(activity, LoginActivity.class)); - }) - ); - - items.add( - new MaterialAboutActionItem( - getString(R.string.settings_profile_notifications_text), - getString(R.string.settings_profile_notifications_subtext), - icon(CommunityMaterial.Icon2.cmd_filter_outline, iconSizeDp, iconColor) - ) - .setOnClickAction(() -> { - new NotificationFilterDialog(activity, null, null); - }) - ); - - items.add( - new MaterialAboutActionItem( - getString(R.string.settings_profile_remove_text), - getString(R.string.settings_profile_remove_subtext), - icon(SzkolnyFont.Icon.szf_delete_empty_outline, iconSizeDp, iconColor) - ) - .setOnClickAction(() -> { - new ProfileRemoveDialog(activity, app.getProfile().getId(), app.getProfile().getName(), false, null); - }) - ); - - items.add(getMoreItem(() -> addCardItems(CARD_PROFILE, getProfileCard(true)))); - } - else { - - items.add( - new MaterialAboutSwitchItem.Builder() - .text(R.string.settings_profile_sync_text) - .subText(R.string.settings_profile_sync_subtext) - .icon(icon(CommunityMaterial.Icon.cmd_account_convert, iconSizeDp, iconColor)) - .setChecked(app.getProfile().getSyncEnabled()) - .setOnCheckedChanged(((item, isChecked) -> { - app.getProfile().setSyncEnabled(isChecked); - app.profileSave(); - return true; - })) - .build() - ); - - } - return items; - } - - /* _______ _ - |__ __| | - | | | |__ ___ _ __ ___ ___ - | | | '_ \ / _ \ '_ ` _ \ / _ \ - | | | | | | __/ | | | | | __/ - |_| |_| |_|\___|_| |_| |_|\__*/ - private ArrayList getThemeCard(boolean expandedOnly) { - ArrayList items = new ArrayList<>(); - if (!expandedOnly) { - - Date today = Date.getToday(); - if (today.month == 12 || today.month == 1) { - items.add( - new MaterialAboutSwitchItem.Builder() - .text(R.string.settings_theme_snowfall_text) - .subText(R.string.settings_theme_snowfall_subtext) - .icon(icon(CommunityMaterial.Icon3.cmd_snowflake, iconSizeDp, iconColor)) - .setChecked(app.getConfig().getUi().getSnowfall()) - .setOnCheckedChanged((item, isChecked) -> { - app.getConfig().getUi().setSnowfall(isChecked); - activity.recreate(); - return true; - }) - .build() - ); - } - - items.add( - new MaterialAboutActionItem( - getString(R.string.settings_theme_theme_text), - Themes.INSTANCE.getThemeName(activity), - icon(CommunityMaterial.Icon3.cmd_palette_outline, iconSizeDp, iconColor) - ) - .setOnClickAction(() -> { - new MaterialDialog.Builder(activity) - .title(R.string.settings_theme_theme_text) - .items(Themes.INSTANCE.getThemeNames(activity)) - .itemsCallbackSingleChoice(app.getConfig().getUi().getTheme(), (dialog, itemView, which, text) -> { - if (app.getConfig().getUi().getTheme() == which) - return true; - app.getConfig().getUi().setTheme(which); - Themes.INSTANCE.setThemeInt(app.getConfig().getUi().getTheme()); - activity.recreate(); - return true; - }) - .show(); - }) - ); - - items.add( - new MaterialAboutSwitchItem.Builder() - .text(R.string.settings_theme_mini_drawer_text) - .subText(R.string.settings_theme_mini_drawer_subtext) - .icon(icon(CommunityMaterial.Icon.cmd_dots_vertical, iconSizeDp, iconColor)) - .setChecked(app.getConfig().getUi().getMiniMenuVisible()) - .setOnCheckedChanged((item, isChecked) -> { - // 0,1 1 - // 0,0 0 - // 1,1 0 - // 1,0 1 - app.getConfig().getUi().setMiniMenuVisible(isChecked); - activity.getNavView().drawer.setMiniDrawerVisiblePortrait(isChecked); - return true; - }) - .build() - ); - - items.add(getMoreItem(() -> addCardItems(CARD_THEME, getThemeCard(true)))); - } - else { - - items.add( - new MaterialAboutActionItem( - getString(R.string.settings_theme_mini_drawer_buttons_text), - null, - icon(CommunityMaterial.Icon2.cmd_format_list_checks, iconSizeDp, iconColor) - ) - .setOnClickAction(() -> { - List buttonIds = new ArrayList<>(); - buttonIds.add(MainActivity.DRAWER_ITEM_HOME); - buttonIds.add(MainActivity.DRAWER_ITEM_TIMETABLE); - buttonIds.add(MainActivity.DRAWER_ITEM_AGENDA); - buttonIds.add(MainActivity.DRAWER_ITEM_GRADES); - buttonIds.add(MainActivity.DRAWER_ITEM_MESSAGES); - buttonIds.add(MainActivity.DRAWER_ITEM_HOMEWORK); - buttonIds.add(MainActivity.DRAWER_ITEM_BEHAVIOUR); - buttonIds.add(MainActivity.DRAWER_ITEM_ATTENDANCE); - buttonIds.add(MainActivity.DRAWER_ITEM_ANNOUNCEMENTS); - buttonIds.add(MainActivity.DRAWER_ITEM_NOTIFICATIONS); - buttonIds.add(MainActivity.DRAWER_ITEM_SETTINGS); - //buttonIds.add(MainActivity.DRAWER_ITEM_DEBUG); - List buttonCaptions = new ArrayList<>(); - buttonCaptions.add(getString(R.string.menu_home_page)); - buttonCaptions.add(getString(R.string.menu_timetable)); - buttonCaptions.add(getString(R.string.menu_agenda)); - buttonCaptions.add(getString(R.string.menu_grades)); - buttonCaptions.add(getString(R.string.menu_messages)); - buttonCaptions.add(getString(R.string.menu_homework)); - buttonCaptions.add(getString(R.string.menu_notices)); - buttonCaptions.add(getString(R.string.menu_attendance)); - buttonCaptions.add(getString(R.string.menu_announcements)); - buttonCaptions.add(getString(R.string.menu_notifications)); - buttonCaptions.add(getString(R.string.menu_settings)); - //buttonCaptions.add(getString(R.string.title_debugging)); - List selectedIds = new ArrayList<>(); - for (int id: app.getConfig().getUi().getMiniMenuButtons()) { - selectedIds.add(buttonIds.indexOf(id)); - } - new MaterialDialog.Builder(activity) - .title(R.string.settings_theme_mini_drawer_buttons_dialog_title) - .content(getString(R.string.settings_theme_mini_drawer_buttons_dialog_text)) - .items(buttonCaptions) - .itemsCallbackMultiChoice(selectedIds.toArray(new Integer[0]), (dialog, which, text) -> { - List list = new ArrayList<>(); - for (int index: which) { - if (index == -1) - continue; - // wtf - - int id = buttonIds.get(index); - list.add(id); - } - app.getConfig().getUi().setMiniMenuButtons(list); - activity.setDrawerItems(); - activity.getDrawer().updateBadges(); - return true; - }) - .positiveText(R.string.ok) - .show(); - }) - ); - - items.add( - new MaterialAboutActionItem( - getString(R.string.settings_theme_drawer_header_text), - null, - icon(CommunityMaterial.Icon2.cmd_image_outline, iconSizeDp, iconColor) - ) - .setOnClickAction(() -> { - if (app.getConfig().getUi().getHeaderBackground() != null) { - new MaterialDialog.Builder(activity) - .title(R.string.what_do_you_want_to_do) - .items(getString(R.string.settings_theme_drawer_header_dialog_set), getString(R.string.settings_theme_drawer_header_dialog_restore)) - .itemsCallback((dialog, itemView, position, text) -> { - if (position == 0) { - startActivityForResult(CropImage.getPickImageChooserIntent(activity), 22); - } else { - MainActivity ac = (MainActivity) getActivity(); - app.getConfig().getUi().setHeaderBackground(null); - if (ac != null) { - ac.getDrawer().setAccountHeaderBackground(null); - ac.getDrawer().open(); - } - } - }) - .show(); - } - else { - startActivityForResult(CropImage.getPickImageChooserIntent(activity), 22); - } - }) - ); - - items.add( - new MaterialAboutActionItem( - getString(R.string.settings_theme_app_background_text), - getString(R.string.settings_theme_app_background_subtext), - icon(CommunityMaterial.Icon2.cmd_image_filter_hdr, iconSizeDp, iconColor) - ) - .setOnClickAction(() -> { - if (app.getConfig().getUi().getAppBackground() != null) { - new MaterialDialog.Builder(activity) - .title(R.string.what_do_you_want_to_do) - .items(getString(R.string.settings_theme_app_background_dialog_set), getString(R.string.settings_theme_app_background_dialog_restore)) - .itemsCallback((dialog, itemView, position, text) -> { - if (position == 0) { - startActivityForResult(CropImage.getPickImageChooserIntent(activity), 23); - } else { - app.getConfig().getUi().setAppBackground(null); - activity.recreate(); - } - }) - .show(); - } - else { - startActivityForResult(CropImage.getPickImageChooserIntent(activity), 23); - } - }) - ); - - items.add( - new MaterialAboutSwitchItem.Builder( ) - .text(R.string.settings_theme_open_drawer_on_back_pressed_text) - .icon(icon(CommunityMaterial.Icon3.cmd_menu_open, iconSizeDp, iconColor)) - .setChecked(app.getConfig().getUi().getOpenDrawerOnBackPressed()) - .setOnCheckedChanged((item, isChecked) -> { - app.getConfig().getUi().setOpenDrawerOnBackPressed(isChecked); - return true; - }) - .build() - ); - } - return items; - } - - /* _____ - / ____| - | (___ _ _ _ __ ___ - \___ \| | | | '_ \ / __| - ____) | |_| | | | | (__ - |_____/ \__, |_| |_|\___| - __/ | - |__*/ - private String getSyncCardIntervalSubText() { - - if (app.getConfig().getSync().getInterval() < 60 * 60) - return getString( - R.string.settings_sync_sync_interval_subtext_format, - ExtensionsKt.plural(activity, R.plurals.time_till_minutes, app.getConfig().getSync().getInterval() / 60) - ); - return getString( - R.string.settings_sync_sync_interval_subtext_format, - ExtensionsKt.plural(activity, R.plurals.time_till_hours, app.getConfig().getSync().getInterval() / 60 / 60) + - (app.getConfig().getSync().getInterval() / 60 % 60 == 0 ? - "" : - " " + ExtensionsKt.plural(activity, R.plurals.time_till_minutes, app.getConfig().getSync().getInterval() / 60 % 60) - ) - ); - } - private String getSyncCardQuietHoursSubText() { - if (app.getConfig().getSync().getQuietHoursStart() == null || app.getConfig().getSync().getQuietHoursEnd() == null) - return ""; - return getString( - app.getConfig().getSync().getQuietHoursStart().getValue() >= app.getConfig().getSync().getQuietHoursEnd().getValue() ? R.string.settings_sync_quiet_hours_subtext_next_day_format : R.string.settings_sync_quiet_hours_subtext_format, - app.getConfig().getSync().getQuietHoursStart().getStringHM(), - app.getConfig().getSync().getQuietHoursEnd().getStringHM() - ); - } - private MaterialAboutItem getSyncCardWifiItem() { - return new MaterialAboutSwitchItem.Builder() - .text(R.string.settings_sync_wifi_text) - .subText(R.string.settings_sync_wifi_subtext) - .icon(icon(CommunityMaterial.Icon3.cmd_wifi_strength_2, iconSizeDp, iconColor)) - .setChecked(app.getConfig().getSync().getOnlyWifi()) - .setOnCheckedChanged((item, isChecked) -> { - app.getConfig().getSync().setOnlyWifi(isChecked); - SyncWorker.Companion.rescheduleNext(app); - return true; - }) - .build(); - } - private MaterialAboutActionSwitchItem syncCardIntervalItem; - private MaterialAboutActionSwitchItem syncCardQuietHoursItem; - private ArrayList getSyncCard(boolean expandedOnly) { - ArrayList items = new ArrayList<>(); - if (!expandedOnly) { - - syncCardIntervalItem = new MaterialAboutActionSwitchItem.Builder() - .text(R.string.settings_sync_sync_interval_text) - .subText(R.string.settings_sync_sync_interval_subtext_disabled) - .icon(icon(CommunityMaterial.Icon.cmd_download_outline, iconSizeDp, iconColor)) - .build(); - syncCardIntervalItem.setSubTextChecked(getSyncCardIntervalSubText()); - syncCardIntervalItem.setChecked(app.getConfig().getSync().getEnabled()); - syncCardIntervalItem.setOnClickAction(() -> { - List intervalNames = new ArrayList<>(); - if (App.Companion.getDebugMode() && false) { - intervalNames.add(ExtensionsKt.plural(activity, R.plurals.time_till_seconds, 30)); - intervalNames.add(ExtensionsKt.plural(activity, R.plurals.time_till_minutes, 2)); - } - intervalNames.add(ExtensionsKt.plural(activity, R.plurals.time_till_minutes, 30)); - intervalNames.add(ExtensionsKt.plural(activity, R.plurals.time_till_minutes, 45)); - intervalNames.add(ExtensionsKt.plural(activity, R.plurals.time_till_hours, 1)); - intervalNames.add(ExtensionsKt.plural(activity, R.plurals.time_till_hours, 1)+" "+ ExtensionsKt.plural(activity, R.plurals.time_till_minutes, 30)); - intervalNames.add(ExtensionsKt.plural(activity, R.plurals.time_till_hours, 2)); - intervalNames.add(ExtensionsKt.plural(activity, R.plurals.time_till_hours, 3)); - intervalNames.add(ExtensionsKt.plural(activity, R.plurals.time_till_hours, 4)); - List intervals = new ArrayList<>(); - if (App.Companion.getDebugMode() && false) { - intervals.add(30); - intervals.add(2 * 60); - } - intervals.add(30 * 60); - intervals.add(45 * 60); - intervals.add(60 * 60); - intervals.add(90 * 60); - intervals.add(120 * 60); - intervals.add(180 * 60); - intervals.add(240 * 60); - new MaterialDialog.Builder(activity) - .title(getString(R.string.settings_sync_sync_interval_dialog_title)) - .content(getString(R.string.settings_sync_sync_interval_dialog_text)) - .items(intervalNames) - .itemsCallbackSingleChoice(intervals.indexOf(app.getConfig().getSync().getInterval()), (dialog, itemView, which, text) -> { - app.getConfig().getSync().setInterval(intervals.get(which)); - syncCardIntervalItem.setSubTextChecked(getSyncCardIntervalSubText()); - syncCardIntervalItem.setChecked(true); - if (!app.getConfig().getSync().getEnabled()) { - addCardItem(CARD_SYNC, 1, getSyncCardWifiItem()); - } - else { - refreshMaterialAboutList(); - } - app.getConfig().getSync().setEnabled(true); - // app.appConfig modifications have to surround syncCardIntervalItem and those ifs - SyncWorker.Companion.rescheduleNext(app); - return true; - }) - .show(); - }); - syncCardIntervalItem.setOnCheckedChangedAction((item, isChecked) -> { - if (isChecked && !app.getConfig().getSync().getEnabled()) { - addCardItem(CARD_SYNC, 1, getSyncCardWifiItem()); - } - else if (!isChecked) { - removeCardItem(CARD_SYNC, 1); - } - app.getConfig().getSync().setEnabled(isChecked); - SyncWorker.Companion.rescheduleNext(app); - return true; - }); - items.add(syncCardIntervalItem); - - if (app.getConfig().getSync().getEnabled()) { - items.add(getSyncCardWifiItem()); - } - - /* items.add( - new MaterialAboutSwitchItem( - "Cisza na lekcjach", - "Nie odtwarzaj dźwięku powiadomień podczas lekcji", - icon(CommunityMaterial.Icon2.cmd_volume_off, iconSizeDp, iconColor) - ) - .setChecked(app.appConfig.quietDuringLessons) - .setOnChangeAction((isChecked) -> { - app.appConfig.quietDuringLessons = isChecked; - app.saveConfig("quietDuringLessons"); - return true; - }) - );*/ - - - syncCardQuietHoursItem = new MaterialAboutActionSwitchItem.Builder() - .text(R.string.settings_sync_quiet_hours_text) - .subText(R.string.settings_sync_quiet_hours_subtext_disabled) - .icon(icon(CommunityMaterial.Icon.cmd_bell_sleep_outline, iconSizeDp, iconColor)) - .build(); - syncCardQuietHoursItem.setChecked(app.getConfig().getSync().getQuietHoursEnabled()); - syncCardQuietHoursItem.setSubTextChecked(getSyncCardQuietHoursSubText()); - syncCardQuietHoursItem.setOnClickAction(() -> { - new MaterialDialog.Builder(activity) - .title(R.string.settings_sync_quiet_hours_dialog_title) - .items( - getString(R.string.settings_sync_quiet_hours_set_beginning), - getString(R.string.settings_sync_quiet_hours_set_end) - ) - .itemsCallback((dialog, itemView, position, text) -> { - if (position == 0) { - // set beginning - Time time = app.getConfig().getSync().getQuietHoursStart(); - if (time == null) - time = new Time(22, 30, 0); - Time timeEnd = app.getConfig().getSync().getQuietHoursEnd(); - if (timeEnd == null) - app.getConfig().getSync().setQuietHoursEnd(new Time(5, 30, 0)); - TimePickerDialog.newInstance((v2, hourOfDay, minute, second) -> { - app.getConfig().getSync().setQuietHoursEnabled(true); - app.getConfig().getSync().setQuietHoursStart(new Time(hourOfDay, minute, second)); - syncCardQuietHoursItem.setChecked(true); - syncCardQuietHoursItem.setSubTextChecked(getSyncCardQuietHoursSubText()); - refreshMaterialAboutList(); - }, time.hour, time.minute, 0, true).show(activity.getSupportFragmentManager(), "TimePickerDialog"); - } - else { - // set end - Time time = app.getConfig().getSync().getQuietHoursEnd(); - if (time == null) - time = new Time(5, 30, 0); - Time timeStart = app.getConfig().getSync().getQuietHoursStart(); - if (timeStart == null) - app.getConfig().getSync().setQuietHoursStart(new Time(22, 30, 0)); - TimePickerDialog.newInstance((v2, hourOfDay, minute, second) -> { - app.getConfig().getSync().setQuietHoursEnabled(true); - app.getConfig().getSync().setQuietHoursEnd(new Time(hourOfDay, minute, second)); - syncCardQuietHoursItem.setChecked(true); - syncCardQuietHoursItem.setSubTextChecked(getSyncCardQuietHoursSubText()); - refreshMaterialAboutList(); - }, time.hour, time.minute, 0, true).show(activity.getSupportFragmentManager(), "TimePickerDialog"); - } - }) - .show(); - }); - syncCardQuietHoursItem.setOnCheckedChangedAction((item, isChecked) -> { - app.getConfig().getSync().setQuietHoursEnabled(isChecked); - if (isChecked && app.getConfig().getSync().getQuietHoursStart() == null) { - app.getConfig().getSync().setQuietHoursStart(new Time(22, 30, 0)); - app.getConfig().getSync().setQuietHoursEnd(new Time(5, 30, 0)); - syncCardQuietHoursItem.setSubTextChecked(getSyncCardQuietHoursSubText()); - refreshMaterialAboutList(); - } - return true; - }); - items.add(syncCardQuietHoursItem); - - items.add( - new MaterialAboutActionItem( - getString(R.string.settings_sync_web_push_text), - getString(R.string.settings_sync_web_push_subtext), - icon(CommunityMaterial.Icon2.cmd_laptop, iconSizeDp, iconColor) - ) - .setOnClickAction(() -> { - activity.loadTarget(MainActivity.TARGET_WEB_PUSH, null); - }) - ); - - items.add(getMoreItem(() -> addCardItems(CARD_SYNC, getSyncCard(true)))); - } - else { - // TODO: 2019-04-27 add notification sound options: szkolny.eu, system default, custom - /*items.add( - new MaterialAboutActionItem( - "Dźwięk powiadomień", - "Szkolny.eu", - icon(CommunityMaterial.Icon2.cmd_volume_high, iconSizeDp, iconColor) - ) - .setOnClickAction(() -> { - - }) - );*/ - - items.add( - new MaterialAboutSwitchItem.Builder() - .text(R.string.settings_sync_updates_text) - .icon(icon(CommunityMaterial.Icon.cmd_cellphone_arrow_down, iconSizeDp, iconColor)) - .setChecked(app.getConfig().getSync().getNotifyAboutUpdates()) - .setOnCheckedChanged((item, isChecked) -> { - app.getConfig().getSync().setNotifyAboutUpdates(isChecked); - UpdateWorker.Companion.rescheduleNext(app); - return true; - }) - .build() - ); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - items.add( - new MaterialAboutActionItem( - getString(R.string.settings_sync_notifications_settings_text), - getString(R.string.settings_sync_notifications_settings_subtext), - icon(CommunityMaterial.Icon.cmd_cog_outline, iconSizeDp, iconColor) - ) - .setOnClickAction(() -> { - String channel = app.getNotificationChannelsManager().getData().getKey(); - Intent intent = new Intent(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - intent.addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK); - intent.setAction(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS); - intent.putExtra(Settings.EXTRA_CHANNEL_ID, channel); - intent.putExtra(Settings.EXTRA_APP_PACKAGE, activity.getPackageName()); - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - if (channel != null) { - intent.setAction(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS); - intent.putExtra(Settings.EXTRA_CHANNEL_ID, channel); - } else { - intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS); - } - intent.putExtra(Settings.EXTRA_APP_PACKAGE, activity.getPackageName()); - } else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { - intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS); - intent.putExtra(Settings.EXTRA_APP_PACKAGE, activity.getPackageName()); - } else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){ - intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS); - intent.putExtra("app_package", activity.getPackageName()); - intent.putExtra("app_uid", activity.getApplicationInfo().uid); - } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) { - intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - intent.addCategory(Intent.CATEGORY_DEFAULT); - intent.setData(Uri.parse("package:" + activity.getPackageName())); - } - activity.startActivity(intent); - }) - ); - } - } - return items; - } - - /* _____ _ _ - | __ \ (_) | | - | |__) |___ __ _ _ ___| |_ ___ _ __ - | _ // _ \/ _` | / __| __/ _ \ '__| - | | \ \ __/ (_| | \__ \ || __/ | - |_| \_\___|\__, |_|___/\__\___|_| - __/ | - |__*/ - private String getRegisterCardAverageModeSubText() { - switch (app.getConfig().forProfile().getGrades().getYearAverageMode()) { - default: - case YEAR_1_AVG_2_AVG: - return getString(R.string.settings_register_avg_mode_0_short); - case YEAR_1_SEM_2_AVG: - return getString(R.string.settings_register_avg_mode_1_short); - case YEAR_1_AVG_2_SEM: - return getString(R.string.settings_register_avg_mode_2_short); - case YEAR_1_SEM_2_SEM: - return getString(R.string.settings_register_avg_mode_3_short); - case YEAR_ALL_GRADES: - return getString(R.string.settings_register_avg_mode_4_short); - } - } - private String getRegisterCardBellSyncSubText() { - if (app.getConfig().getTimetable().getBellSyncDiff() == null) - return getString(R.string.settings_register_bell_sync_subtext_disabled); - return getString( - R.string.settings_register_bell_sync_subtext_format, - (app.getConfig().getTimetable().getBellSyncMultiplier() == -1 ? "-" : "+") + app.getConfig().getTimetable().getBellSyncDiff().getStringHMS() - ); - } - private MaterialAboutItem getRegisterCardSharedEventsItem() { - return new MaterialAboutSwitchItem.Builder() - .text(R.string.settings_register_shared_events_text) - .subText(R.string.settings_register_shared_events_subtext) - .icon(icon(CommunityMaterial.Icon3.cmd_share_outline, iconSizeDp, iconColor)) - .setChecked(app.getProfile().getEnableSharedEvents()) - .setOnCheckedChanged((item, isChecked) -> { - app.getProfile().setEnableSharedEvents(isChecked); - app.profileSave(); - if (isChecked) new MaterialDialog.Builder(activity) - .title(R.string.event_sharing) - .content(getString(R.string.settings_register_shared_events_dialog_enabled_text)) - .positiveText(R.string.ok) - .show(); - else new MaterialDialog.Builder(activity) - .title(R.string.event_sharing) - .content(getString(R.string.settings_register_shared_events_dialog_disabled_text)) - .positiveText(R.string.ok) - .show(); - return true; - }) - .build(); - } - - private MaterialAboutSwitchItem registerCardAllowRegistrationItem; - private MaterialAboutActionItem registerCardBellSyncItem; - private ArrayList getRegisterCard(boolean expandedOnly) { - ArrayList items = new ArrayList<>(); - if (!expandedOnly) { - items.add(new MaterialAboutActionItem( - getString(R.string.menu_grades_config), - null, - icon(CommunityMaterial.Icon3.cmd_numeric_5_box_outline, iconSizeDp, iconColor) - ).setOnClickAction(() -> new GradesConfigDialog(activity, false, null, null))); - - items.add(new MaterialAboutActionItem( - getString(R.string.menu_attendance_config), - null, - icon(CommunityMaterial.Icon.cmd_calendar_remove_outline, iconSizeDp, iconColor) - ).setOnClickAction(() -> new AttendanceConfigDialog(activity, false, null, null))); - - registerCardAllowRegistrationItem = new MaterialAboutSwitchItem.Builder() - .text(R.string.settings_register_allow_registration_text) - .subText(R.string.settings_register_allow_registration_subtext) - .icon(icon(CommunityMaterial.Icon.cmd_account_circle_outline, iconSizeDp, iconColor)) - .build(); - registerCardAllowRegistrationItem.setChecked(app.getProfile().getRegistration() == REGISTRATION_ENABLED); - registerCardAllowRegistrationItem.setOnCheckedChangedAction((item, isChecked) -> { - if (isChecked) new MaterialDialog.Builder(activity) - .title(getString(R.string.settings_register_allow_registration_dialog_enabled_title)) - .content(getString(R.string.settings_register_allow_registration_dialog_enabled_text)) - .positiveText(R.string.i_agree) - .negativeText(R.string.not_now) - .onPositive(((dialog, which) -> { - registerCardAllowRegistrationItem.setChecked(true); - app.getProfile().setRegistration(REGISTRATION_ENABLED); - app.profileSave(); - addCardItem(CARD_REGISTER, 3, getRegisterCardSharedEventsItem()); - refreshMaterialAboutList(); - })) - .show(); - else new MaterialDialog.Builder(activity) - .title(getString(R.string.settings_register_allow_registration_dialog_disabled_title)) - .content(getString(R.string.settings_register_allow_registration_dialog_disabled_text)) - .positiveText(R.string.ok) - .negativeText(R.string.cancel) - .onPositive(((dialog, which) -> { - registerCardAllowRegistrationItem.setChecked(false); - app.getProfile().setRegistration(REGISTRATION_DISABLED); - app.profileSave(); - removeCardItem(CARD_REGISTER, 3); - refreshMaterialAboutList(); - MaterialDialog progressDialog = new MaterialDialog.Builder(activity) - .title(getString(R.string.settings_register_allow_registration_dialog_disabling_title)) - .content(getString(R.string.settings_register_allow_registration_dialog_disabling_text)) - .positiveText(R.string.ok) - .negativeText(R.string.abort) - .show(); - AsyncTask.execute(() -> { - new SzkolnyApi(app).runCatching(szkolnyApi -> null, szkolnyApi -> null); - activity.runOnUiThread(() -> { - progressDialog.dismiss(); - Toast.makeText(activity, getString(R.string.settings_register_allow_registration_dialog_disabling_finished), Toast.LENGTH_SHORT).show(); - }); - }); - })) - .show(); - return false; - }); - items.add(registerCardAllowRegistrationItem); - - if (app.getProfile().getRegistration() == REGISTRATION_ENABLED) { - items.add(getRegisterCardSharedEventsItem()); - } - - items.add(getMoreItem(() -> addCardItems(CARD_REGISTER, getRegisterCard(true)))); - } - else { - registerCardBellSyncItem = new MaterialAboutActionItem( - getString(R.string.settings_register_bell_sync_text), - getRegisterCardBellSyncSubText(), - icon(SzkolnyFont.Icon.szf_alarm_bell_outline, iconSizeDp, iconColor) - ); - registerCardBellSyncItem.setOnClickAction(() -> { - new MaterialDialog.Builder(activity) - .title(R.string.bell_sync_title) - .content(R.string.bell_sync_adjust_content) - .positiveText(R.string.ok) - .negativeText(R.string.cancel) - .neutralText(R.string.reset) - .inputRangeRes(8, 8, R.color.md_red_500) - .input("±H:MM:SS", - (app.getConfig().getTimetable().getBellSyncDiff() != null - ? (app.getConfig().getTimetable().getBellSyncMultiplier() == -1 ? "-" : "+") + app.getConfig().getTimetable().getBellSyncDiff().getStringHMS() - : ""), (dialog, input) -> { - if (input == null) - return; - if (input.length() < 8) { - Toast.makeText(activity, R.string.bell_sync_adjust_error, Toast.LENGTH_SHORT).show(); - return; - } - if (input.charAt(2) != ':' || input.charAt(5) != ':') { - Toast.makeText(activity, R.string.bell_sync_adjust_error, Toast.LENGTH_SHORT).show(); - return; - } - if (input.charAt(0) == '+') { - app.getConfig().getTimetable().setBellSyncMultiplier(1); - } - else if (input.charAt(0) == '-') { - app.getConfig().getTimetable().setBellSyncMultiplier(-1); - } - else { - Toast.makeText(activity, R.string.bell_sync_adjust_error, Toast.LENGTH_SHORT).show(); - return; - } - - int hour; - int minute; - int second; - try { - hour = Integer.parseInt(input.charAt(1) + ""); - minute = Integer.parseInt(input.charAt(3) + "" + input.charAt(4)); - second = Integer.parseInt(input.charAt(6) + "" + input.charAt(7)); - } - catch (Exception e) { - e.printStackTrace(); - Toast.makeText(activity, R.string.bell_sync_adjust_error, Toast.LENGTH_SHORT).show(); - return; - } - - app.getConfig().getTimetable().setBellSyncDiff(new Time(hour, minute, second)); - registerCardBellSyncItem.setSubText(getRegisterCardBellSyncSubText()); - refreshMaterialAboutList(); - }) - .onNeutral(((dialog, which) -> { - app.getConfig().getTimetable().setBellSyncDiff(null); - app.getConfig().getTimetable().setBellSyncMultiplier(0); - registerCardBellSyncItem.setSubText(getRegisterCardBellSyncSubText()); - refreshMaterialAboutList(); - })) - .show(); - }); - items.add(registerCardBellSyncItem); - - items.add( - new MaterialAboutSwitchItem.Builder() - .text(R.string.settings_register_count_in_seconds_text) - .subText(R.string.settings_register_count_in_seconds_subtext) - .icon(icon(CommunityMaterial.Icon3.cmd_timer, iconSizeDp, iconColor)) - .setChecked(app.getConfig().getTimetable().getCountInSeconds()) - .setOnCheckedChanged((item, isChecked) -> { - app.getConfig().getTimetable().setCountInSeconds(isChecked); - return true; - }) - .build() - ); - - if (app.getProfile().getLoginStoreType() == LoginStore.LOGIN_TYPE_LIBRUS) { - items.add( - new MaterialAboutSwitchItem.Builder() - .text(R.string.settings_register_show_teacher_absences_text) - .icon(icon(CommunityMaterial.Icon.cmd_account_arrow_right_outline, iconSizeDp, iconColor)) - .setChecked(app.getProfile().getStudentData("showTeacherAbsences", true)) - .setOnCheckedChanged((item, isChecked) -> { - app.getProfile().putStudentData("showTeacherAbsences", isChecked); - app.profileSave(); - return true; - }) - .build() - ); - } - - if (App.Companion.getDevMode()) { - items.add( - new MaterialAboutSwitchItem.Builder() - .text(R.string.settings_register_hide_sticks_from_old) - .icon(icon(CommunityMaterial.Icon3.cmd_numeric_1_box_outline, iconSizeDp, iconColor)) - .setChecked(app.getConfig().forProfile().getGrades().getHideSticksFromOld()) - .setOnCheckedChanged((item, isChecked) -> { - app.getConfig().forProfile().getGrades().setHideSticksFromOld(isChecked); - return true; - }) - .build() - ); - } - - } - return items; - } - - /* _ _ - /\ | | | | - / \ | |__ ___ _ _| |_ - / /\ \ | '_ \ / _ \| | | | __| - / ____ \| |_) | (_) | |_| | |_ - /_/ \_\_.__/ \___/ \__,_|\_*/ - private MaterialAboutActionItem pref_about_version; - private ArrayList getAboutCard(boolean expandedOnly) { - primaryTextOnPrimaryBg = 0xffffffff;//getColorFromAttr(activity, R.attr.colorOnPrimary); - secondaryTextOnPrimaryBg = 0xd0ffffff;//activity.getResources().getColor(R.color.secondaryTextLight); - - ArrayList items = new ArrayList<>(); - if (!expandedOnly) { - items.add(new MaterialAboutTitleItem.Builder() - .text(R.string.app_name) - .desc(R.string.settings_about_title_subtext) - .icon(R.mipmap.ic_splash) - .build()); - - pref_about_version = new MaterialAboutActionItem.Builder() - .text(R.string.settings_about_version_text) - .subText(BuildConfig.VERSION_NAME + ", " + BuildConfig.BUILD_TYPE) - .icon(icon(CommunityMaterial.Icon2.cmd_information_outline, iconSizeDp, primaryTextOnPrimaryBg)) - .build(); - final int[] clickCounter = {0}; - pref_about_version.setOnClickAction(() -> { - if (6 - clickCounter[0] != 0) { - Toast.makeText(activity, ("\ud83d\ude02"), Toast.LENGTH_SHORT).show(); - } - refreshMaterialAboutList(); - clickCounter[0] = clickCounter[0] + 1; - if (clickCounter[0] > 6) { - final MediaPlayer mp = MediaPlayer.create(activity, R.raw.ogarnij_sie); - mp.start(); - clickCounter[0] = 0; - } - }); - items.add(pref_about_version); - - items.add(new MaterialAboutActionItem.Builder() - .text(R.string.settings_about_privacy_policy_text) - .icon(icon(CommunityMaterial.Icon3.cmd_shield_outline, iconSizeDp, primaryTextOnPrimaryBg)) - .setOnClickAction(ConvenienceBuilder.createWebsiteOnClickAction(activity, Uri.parse("https://szkolny.eu/privacy-policy"))) - .build()); - - items.add(new MaterialAboutActionItem.Builder() - .text(R.string.settings_about_discord_text) - .subText(R.string.settings_about_discord_subtext) - .icon(icon(SzkolnyFont.Icon.szf_discord_outline, iconSizeDp, primaryTextOnPrimaryBg)) - .setOnClickAction(ConvenienceBuilder.createWebsiteOnClickAction(activity, Uri.parse("https://szkolny.eu/discord"))) - .build()); - - items.add(new MaterialAboutActionItem.Builder() - .text(R.string.settings_about_language_text) - .subText(R.string.settings_about_language_subtext) - .icon(icon(CommunityMaterial.Icon3.cmd_translate, iconSizeDp, primaryTextOnPrimaryBg)) - .setOnClickAction(() -> { - new MaterialDialog.Builder(activity) - .title(getString(R.string.app_language_dialog_title)) - .content(getString(R.string.app_language_dialog_text)) - .items(getString(R.string.language_system), getString(R.string.language_polish), getString(R.string.language_english), getString(R.string.language_german)) - .itemsCallbackSingleChoice(app.getConfig().getUi().getLanguage() == null ? 0 : app.getConfig().getUi().getLanguage().equals("pl") ? 1 : app.getConfig().getUi().getLanguage().equals("en") ? 2 : 3, (dialog, itemView, which, text) -> { - switch (which) { - case 0: - app.getConfig().getUi().setLanguage(null); - initDefaultLocale(); - break; - case 1: - app.getConfig().getUi().setLanguage("pl"); - break; - case 2: - app.getConfig().getUi().setLanguage("en"); - break; - case 3: - app.getConfig().getUi().setLanguage("de"); - break; - } - activity.recreate(MainActivity.DRAWER_ITEM_SETTINGS); - return true; - }) - .show(); - }) - .build()); - - items.add(getMoreItem(() -> addCardItems(CARD_ABOUT, getAboutCard(true)))); - } - else { - items.add(new MaterialAboutActionItem.Builder() - .text(R.string.settings_about_update_text) - .subText(R.string.settings_about_update_subtext) - .icon(icon(CommunityMaterial.Icon3.cmd_update, iconSizeDp, primaryTextOnPrimaryBg)) - .setOnClickAction(() -> { - //open browser or intent here - NetworkUtils net = new NetworkUtils(app); - if (!net.isOnline()) { - new MaterialDialog.Builder(activity) - .title(R.string.you_are_offline_title) - .content(R.string.you_are_offline_text) - .positiveText(R.string.ok) - .show(); - } else { - AsyncTask.execute(() -> { - new UpdateWorker.JavaWrapper(app); - }); - } - }) - .build()); - - items.add(new MaterialAboutActionItem.Builder() - .text(R.string.settings_about_changelog_text) - .icon(icon(CommunityMaterial.Icon3.cmd_radar, iconSizeDp, primaryTextOnPrimaryBg)) - .setOnClickAction(() -> new ChangelogDialog(activity, null, null)) - .build()); - - items.add(new MaterialAboutActionItem.Builder() - .text(R.string.settings_about_licenses_text) - .icon(icon(CommunityMaterial.Icon.cmd_code_braces, iconSizeDp, primaryTextOnPrimaryBg)) - .setOnClickAction(() -> { - Intent intent = new Intent(activity, SettingsLicenseActivity.class); - startActivity(intent); - }) - .build()); - - /*items.add(new MaterialAboutActionItem.Builder() - .text(R.string.settings_about_intro_text) - .icon(icon(CommunityMaterial.Icon2.cmd_projector_screen, iconSizeDp, iconColor)) - .setOnClickAction(() -> { - if (tryingToDevMode[0]) { - if (getParentFragment() instanceof SettingsGeneralFragment) { - ((SettingsGeneralFragment) getParentFragment()).showDevSettings(); - } - tryingToDevMode[0] = false; - return; - } - IntroConnectionFragment.connectionOk = true; - IntroConnectionFragment.httpsOk = (app.requestScheme.equals("https")); - Intent intent = new Intent(activity, MainIntroActivity.class); - IntroSplashFragment.skipAnimation = false; - startActivity(intent); - }) - .build());*/ - - if (App.Companion.getDevMode()) { - items.add(new MaterialAboutActionItem.Builder() - .text(R.string.settings_about_crash_text) - .subText(R.string.settings_about_crash_subtext) - .icon(icon(CommunityMaterial.Icon.cmd_bug_outline, iconSizeDp, primaryTextOnPrimaryBg)) - .setOnClickAction(() -> { - throw new RuntimeException("MANUAL CRASH"); - }) - .build()); - } - } - return items; - } - - @Override - protected MaterialAboutList getMaterialAboutList(Context activityContext) { - if (getActivity() == null || getContext() == null || !isAdded()) - return null; - this.activity = (MainActivity) activityContext; - this.app = (App) activity.getApplication(); - iconColor = Themes.INSTANCE.getPrimaryTextColor(activityContext); - if (app.getProfile() == null) - return new MaterialAboutList.Builder().build(); - - MaterialAboutList materialAboutList = new MaterialAboutList(); - materialAboutList.addCard(getCardWithItems(null, getProfileCard(false))); - materialAboutList.addCard(getCardWithItems(getString(R.string.settings_card_theme_title), getThemeCard(false))); - materialAboutList.addCard(getCardWithItems(getString(R.string.settings_card_sync_title), getSyncCard(false))); - materialAboutList.addCard(getCardWithItems(getString(R.string.settings_card_register_title), getRegisterCard(false))); - //if (configurableEndpoints != null) - // materialAboutList.addCard(getCardWithItems(getString(R.string.settings_sync_customize_title_text), getSyncCustomizeCard(false))); - materialAboutList.addCard(getCardWithItems(null, getAboutCard(false), true)); - - return materialAboutList; - } - - /* _____ _ ____ _ _ - / ____| | | | _ \ | | | | - | | _ _ ___| |_ ___ _ __ ___ | |_) | __ _ ___| | ____ _ _ __ ___ _ _ _ __ __| |___ - | | | | | / __| __/ _ \| '_ ` _ \ | _ < / _` |/ __| |/ / _` | '__/ _ \| | | | '_ \ / _` / __| - | |___| |_| \__ \ || (_) | | | | | | | |_) | (_| | (__| < (_| | | | (_) | |_| | | | | (_| \__ \ - \_____\__,_|___/\__\___/|_| |_| |_| |____/ \__,_|\___|_|\_\__, |_| \___/ \__,_|_| |_|\__,_|___/ - __/ | - |__*/ - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (data == null) { - Toast.makeText(app, "Wystąpił błąd. Spróbuj ponownie", Toast.LENGTH_SHORT).show(); - return; - } - if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE && resultCode == RESULT_OK) { - CropImage.ActivityResult result = CropImage.getActivityResult(data); - - Uri uri = result.getUri(); - - File photoFile = new File(uri.getPath()); - File destFile = new File(getContext().getFilesDir(),"profile"+ app.getProfile().getId() +".jpg"); - if (destFile.exists()) { - destFile.delete(); - destFile = new File(getContext().getFilesDir(),"profile"+ app.getProfile().getId() +".jpg"); - } - - d(TAG, "Source file: "+photoFile.getAbsolutePath()); - d(TAG, "Dest file: "+destFile.getAbsolutePath()); - - if (result.getCropRect().width() > 512 || true) { - Bitmap bigImage = BitmapFactory.decodeFile(uri.getPath()); - Bitmap smallImage = getResizedBitmap(bigImage, 512, 512); - try (FileOutputStream out = new FileOutputStream(destFile)) { - smallImage.compress(Bitmap.CompressFormat.JPEG, 80, out); // bmp is your Bitmap instance - // PNG is a lossless format, the compression factor (100) is ignored - app.getProfile().setImage(destFile.getAbsolutePath()); - app.profileSave(); - profileCardTitleItem.setIcon(getProfileDrawable()); - refreshMaterialAboutList(); - if (photoFile.exists()) { - photoFile.delete(); - } - //((MainActivity)getActivity()).recreateWithTransition(); // TODO somehow update miniDrawer profile picture - } catch (IOException e) { - e.printStackTrace(); - } - } - else { - if (photoFile.renameTo(destFile)) { - // success - app.getProfile().setImage(destFile.getAbsolutePath()); - app.profileSave(); - profileCardTitleItem.setIcon(getProfileDrawable()); - refreshMaterialAboutList(); - //((MainActivity)getActivity()).recreateWithTransition(); // TODO somehow update miniDrawer profile picture - } - else { - // not this time - Toast.makeText(app, R.string.error_occured, Toast.LENGTH_LONG).show(); - } - } - } - else if (requestCode == 21 && resultCode == Activity.RESULT_OK) { - Uri uri = data.getData(); - if (uri != null) { - String path = getRealPathFromURI(activity, uri); - if (path.toLowerCase().endsWith(".gif")) { - app.getProfile().setImage(path); - app.profileSave(); - profileCardTitleItem.setIcon(getProfileDrawable()); - refreshMaterialAboutList(); - } - else { - CropImage.activity(data.getData()) - .setAspectRatio(1, 1) - //.setMaxCropResultSize(512, 512) - .setCropShape(CropImageView.CropShape.OVAL) - .setGuidelines(CropImageView.Guidelines.ON) - .start(activity, this); - } - } - - } - else if (requestCode == 22 && resultCode == Activity.RESULT_OK) { - Uri uri = data.getData(); - if (uri != null) { - app.getConfig().getUi().setHeaderBackground(getRealPathFromURI(getContext(), uri)); - if (activity != null) { - activity.getDrawer().setAccountHeaderBackground(app.getConfig().getUi().getHeaderBackground()); - activity.getDrawer().open(); - } - } - } - else if (requestCode == 23 && resultCode == Activity.RESULT_OK) { - Uri uri = data.getData(); - if (uri != null) { - app.getConfig().getUi().setAppBackground(getRealPathFromURI(getContext(), uri)); - if (activity != null) { - activity.recreate(); - } - } - } - - } -} From 1b271bd20e651782ecbb60ea9757936569416750 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 25 Mar 2021 19:02:23 +0100 Subject: [PATCH 044/113] [EventBus] Fix crash when opening EventManualDialog. --- .../edziennik/ui/dialogs/event/EventManualDialog.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/event/EventManualDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/event/EventManualDialog.kt index db5a2b09..97e34009 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/event/EventManualDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/event/EventManualDialog.kt @@ -84,7 +84,7 @@ class EventManualDialog( if (activity.isFinishing) return@launch onShowListener?.invoke(TAG) - EventBus.getDefault().register(this) + EventBus.getDefault().register(this@EventManualDialog) b = DialogEventManualV2Binding.inflate(activity.layoutInflater) dialog = MaterialAlertDialogBuilder(activity) .setTitle(R.string.dialog_event_manual_title) From a5f5c740c96c123593093a847ac410901482724e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 25 Mar 2021 19:37:25 +0100 Subject: [PATCH 045/113] [UI/Licenses] Update list of open source licenses. --- .../settings/SettingsLicenseActivity.kt | 495 +++++++++++++----- 1 file changed, 350 insertions(+), 145 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsLicenseActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsLicenseActivity.kt index 2e5aaf6f..e0c6be5e 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsLicenseActivity.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsLicenseActivity.kt @@ -3,8 +3,8 @@ package pl.szczodrzynski.edziennik.ui.modules.settings import android.content.Context import android.net.Uri import android.os.Bundle - import com.danielstone.materialaboutlibrary.ConvenienceBuilder +import com.danielstone.materialaboutlibrary.ConvenienceBuilder.createLicenseCard import com.danielstone.materialaboutlibrary.MaterialAboutActivity import com.danielstone.materialaboutlibrary.items.MaterialAboutActionItem import com.danielstone.materialaboutlibrary.model.MaterialAboutCard @@ -14,169 +14,374 @@ import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial import com.mikepenz.iconics.utils.colorInt import com.mikepenz.iconics.utils.sizeDp - -import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.resolveColor import pl.szczodrzynski.edziennik.utils.Themes class SettingsLicenseActivity : MaterialAboutActivity() { var foregroundColor: Int = 0 + private val icon + get() = IconicsDrawable(this).apply { + icon = CommunityMaterial.Icon.cmd_book_outline + colorInt = foregroundColor + sizeDp = 18 + } + override fun onCreate(savedInstanceState: Bundle?) { - val app = application as App - setTheme(Themes.appTheme) - foregroundColor = Themes.getPrimaryTextColor(this) + setTheme( + if (Themes.isDark) + R.style.Theme_MaterialComponents + else + R.style.Theme_MaterialComponents_Light + ) + foregroundColor = if (Themes.isDark) + R.color.primaryTextDark.resolveColor(this) + else + R.color.primaryTextLight.resolveColor(this) super.onCreate(savedInstanceState) } - private fun createLicenseCard( - context: Context, - libraryTitle: CharSequence, - copyrightYear: CharSequence, - copyrightName: CharSequence, - license: OpenSourceLicense, - libraryUrl: String): MaterialAboutCard { - val licenseItem = MaterialAboutActionItem.Builder() - .icon(IconicsDrawable(this).apply { - icon = CommunityMaterial.Icon.cmd_book_outline - colorInt = foregroundColor - sizeDp = 18 - }) - .setIconGravity(MaterialAboutActionItem.GRAVITY_TOP) - .text(libraryTitle) - .subText(String.format(getString(license.resourceId), copyrightYear, copyrightName)) - .setOnClickAction(ConvenienceBuilder.createWebsiteOnClickAction(context, Uri.parse(libraryUrl))) - .build() - - return MaterialAboutCard.Builder().addItem(licenseItem).build() + private fun license( + title: String, + year: String, + copyright: String, + license: OpenSourceLicense, + url: String + ): MaterialAboutCard { + return createLicenseCard(this, icon, title, year, copyright, license).also { + (it.items[0] as MaterialAboutActionItem).onClickAction = + ConvenienceBuilder.createWebsiteOnClickAction( + this, + Uri.parse(url) + ) + } } - override fun getMaterialAboutList(context: Context): MaterialAboutList { + override fun getMaterialAboutList(context: Context) = MaterialAboutList( + license( + "Kotlin", + "2000-2020", + "JetBrains s.r.o. and Kotlin Programming Language contributors.", + OpenSourceLicense.APACHE_2, + "https://github.com/JetBrains/kotlin" + ), - return MaterialAboutList( - createLicenseCard(this, - "OkHttp", - "", - "square", - OpenSourceLicense.APACHE_2, - "https://github.com/square/okhttp/"), - createLicenseCard(this, - "MHttp", - "2018", - "Mot.", - OpenSourceLicense.APACHE_2, - "https://github.com/motcwang/MHttp/"), - createLicenseCard(this, - "AgendaCalendarView", - "2015", - "Thibault Guégan", - OpenSourceLicense.APACHE_2, - "https://github.com/Tibolte/AgendaCalendarView/"), - createLicenseCard(this, - "Material Calendar View", - "2017", - "Applandeo sp. z o.o.", - OpenSourceLicense.APACHE_2, - "https://github.com/Applandeo/Material-Calendar-View/"), - createLicenseCard(this, - "Custom Activity On Crash", - "", - "Eduard Ereza MartĂ­nez (Ereza)", - OpenSourceLicense.APACHE_2, - "https://github.com/Ereza/CustomActivityOnCrash/"), - createLicenseCard(this, - "Android-Iconics", - "2018", - "Mike Penz", - OpenSourceLicense.APACHE_2, - "https://github.com/mikepenz/Android-Iconics/"), - createLicenseCard(this, - "MaterialDrawer", - "2016", - "Mike Penz", - OpenSourceLicense.APACHE_2, - "https://github.com/mikepenz/MaterialDrawer/"), - createLicenseCard(this, - "Material Dialogs", - "2014-2016", - "Aidan Michael Follestad", - OpenSourceLicense.MIT, - "https://github.com/afollestad/material-dialogs/"), - createLicenseCard(this, - "MaterialDateTimePicker", - "2014", - "Wouter Dullaert", - OpenSourceLicense.APACHE_2, - "https://github.com/wdullaer/MaterialDateTimePicker/"), - createLicenseCard(this, - "ColorPicker", - "2016", - "Jared Rummler, 2015 Daniel Nilsson", - OpenSourceLicense.APACHE_2, - "https://github.com/jaredrummler/ColorPicker/"), - createLicenseCard(this, - "material-about-library", - "2016-2018", - "Daniel Stone", - OpenSourceLicense.APACHE_2, - "https://github.com/daniel-stoneuk/material-about-library/"), - createLicenseCard(this, - "material-intro", - "2017", - "Jan Heinrich Reimer", - OpenSourceLicense.MIT, - "https://github.com/heinrichreimer/material-intro/"), - createLicenseCard(this, - "JsonViewer", - "2017", - "smuyyh", - OpenSourceLicense.APACHE_2, - "https://github.com/smuyyh/JsonViewer/"), - createLicenseCard(this, - "ShortcutBadger", - "2014", - "Leo Lin", - OpenSourceLicense.APACHE_2, - "https://github.com/leolin310148/ShortcutBadger/"), - createLicenseCard(this, - "Android Image Cropper", - "2016", - "Arthur Teplitzki, 2013 Edmodo, Inc.", - OpenSourceLicense.APACHE_2, - "https://github.com/ArthurHub/Android-Image-Cropper/"), - createLicenseCard(this, - "Android Swipe Layout", - "2014", - "代码家 (daimajia)", - OpenSourceLicense.MIT, - "https://github.com/daimajia/AndroidSwipeLayout/"), - createLicenseCard(this, - "barcodescanner (ZXing)", - "2014", - "Dushyanth Maguluru", - OpenSourceLicense.APACHE_2, - "https://github.com/dm77/barcodescanner/"), - createLicenseCard(this, - "CircularProgressIndicator", - "2018", - "Anton Kozyriatskyi", - OpenSourceLicense.APACHE_2, - "https://github.com/antonKozyriatskyi/CircularProgressIndicator/") + license( + "Android Jetpack", + "", + "The Android Open Source Project", + OpenSourceLicense.APACHE_2, + "https://github.com/androidx/androidx" + ), + license( + "Material Components for Android", + "2014-2020", + "Google, Inc.", + OpenSourceLicense.APACHE_2, + "https://github.com/material-components/material-components-android" + ), - /*createLicenseCard(this, - "NoNonsense-FilePicker", - "", - "Jonas Kalderstam (spacecowboy)", - OpenSourceLicense.GNU_GPL_3, - "https://github.com/spacecowboy/NoNonsense-FilePicker/")*/ + license( + "OkHttp", + "2019", + "Square, Inc.", + OpenSourceLicense.APACHE_2, + "https://github.com/square/okhttp" + ), + license( + "Retrofit", + "2013", + "Square, Inc.", + OpenSourceLicense.APACHE_2, + "https://github.com/square/retrofit" + ), + + license( + "Gson", + "2008", + "Google Inc.", + OpenSourceLicense.APACHE_2, + "https://github.com/google/gson" + ), + + license( + "jsoup", + "2009-2021", + "Jonathan Hedley", + OpenSourceLicense.MIT, + "https://github.com/jhy/jsoup" + ), + + license( + "jspoon", + "2017", + "Droids On Roids", + OpenSourceLicense.MIT, + "https://github.com/DroidsOnRoids/jspoon" + ), + + license( + "AgendaCalendarView", + "2015", + "Thibault Guégan", + OpenSourceLicense.APACHE_2, + "https://github.com/szkolny-eu/agendacalendarview" + ), + + license( + "CafeBar", + "2017", + "Dani Mahardhika", + OpenSourceLicense.APACHE_2, + "https://github.com/szkolny-eu/cafebar" + ), + + license( + "FSLogin", + "2021", + "kuba2k2", + OpenSourceLicense.MIT, + "https://github.com/szkolny-eu/FSLogin" + ), + + license( + "material-about-library", + "2016-2020", + "Daniel Stone", + OpenSourceLicense.APACHE_2, + "https://github.com/szkolny-eu/material-about-library" + ), + + license( + "MHttp", + "2018", + "Mot.", + OpenSourceLicense.APACHE_2, + "https://github.com/szkolny-eu/mhttp" + ), + + license( + "Nachos for Android", + "2016", + "Hootsuite Media, Inc.", + OpenSourceLicense.APACHE_2, + "https://github.com/szkolny-eu/nachos" + ), + + license( + "Material Number Sliding Picker", + "2019", + "Alessandro Crugnola", + OpenSourceLicense.MIT, + "https://github.com/kuba2k2/NumberSlidingPicker" + ), + + license( + "RecyclerTabLayout", + "2017", + "nshmura", + OpenSourceLicense.APACHE_2, + "https://github.com/kuba2k2/RecyclerTabLayout" + ), + + license( + "Tachyon", + "2019", + "LinkedIn Corporation", + OpenSourceLicense.BSD, + "https://github.com/kuba2k2/Tachyon" + ), + + license( + "Android-Iconics", + "2021", + "Mike Penz", + OpenSourceLicense.APACHE_2, + "https://github.com/mikepenz/Android-Iconics" + ), + + license( + "Custom Activity On Crash library", + "2020", + "Eduard Ereza Martínez", + OpenSourceLicense.APACHE_2, + "https://github.com/Ereza/CustomActivityOnCrash" + ), + + license( + "Material-Calendar-View", + "2017", + "Applandeo sp. z o.o.", + OpenSourceLicense.APACHE_2, + "https://github.com/Applandeo/Material-Calendar-View" + ), + + license( + "Android Swipe Layout", + "2014", + "代码家", + OpenSourceLicense.MIT, + "https://github.com/daimajia/AndroidSwipeLayout" + ), + + license( + "CircularProgressIndicator", + "2018", + "Anton Kozyriatskyi", + OpenSourceLicense.APACHE_2, + "https://github.com/antonKozyriatskyi/CircularProgressIndicator" + ), + + license( + "ChatMessageView", + "2019", + "Tsubasa Nakayama", + OpenSourceLicense.APACHE_2, + "https://github.com/bassaer/ChatMessageView" + ), + + license( + "Android Image Cropper", + "2016 Arthur Teplitzki,", + "2013 Edmodo, Inc.", + OpenSourceLicense.APACHE_2, + "https://github.com/CanHub/Android-Image-Cropper" + ), + + license( + "Chucker", + "2018-2020 Chucker Team,", + "2017 Jeff Gilfelt", + OpenSourceLicense.APACHE_2, + "https://github.com/ChuckerTeam/chucker" + ), + + license( + "Android-Snowfall", + "2016", + "JetRadar", + OpenSourceLicense.APACHE_2, + "https://github.com/JetradarMobile/android-snowfall" + ), + + license( + "UONET+ Request Signer", + "2019", + "Wulkanowy", + OpenSourceLicense.MIT, + "https://github.com/wulkanowy/uonet-request-signer" + ), + + license( + "material-intro", + "2017", + "Jan Heinrich Reimer", + OpenSourceLicense.MIT, + "https://github.com/heinrichreimer/material-intro" + ), + + license( + "HyperLog Android", + "2018", + "HyperTrack", + OpenSourceLicense.MIT, + "https://github.com/hypertrack/hyperlog-android" + ), + + license( + "Color Picker", + "2016 Jared Rummler,", + "2015 Daniel Nilsson", + OpenSourceLicense.APACHE_2, + "https://github.com/jaredrummler/ColorPicker" + ), + + license( + "PowerPermission", + "2020", + "Qifan Yang", + OpenSourceLicense.APACHE_2, + "https://github.com/underwindfall/PowerPermission" + ), + + license( + "Material DateTime Picker", + "2015", + "Wouter Dullaert", + OpenSourceLicense.APACHE_2, + "https://github.com/wdullaer/MaterialDateTimePicker" + ), + + license( + "JsonViewer", + "2017", + "smuyyh", + OpenSourceLicense.APACHE_2, + "https://github.com/smuyyh/JsonViewer" + ), + + license( + "Coil", + "2021", + "Coil Contributors", + OpenSourceLicense.APACHE_2, + "https://github.com/coil-kt/coil" + ), + + license( + "Barcode Scanner (ZXing)", + "2014", + "Dushyanth Maguluru", + OpenSourceLicense.APACHE_2, + "https://github.com/dm77/barcodescanner" + ), + + license( + "AutoFitTextView", + "2014", + "Grantland Chew", + OpenSourceLicense.APACHE_2, + "https://github.com/grantland/android-autofittextview" + ), + + license( + "ShortcutBadger", + "2014", + "Leo Lin", + OpenSourceLicense.APACHE_2, + "https://github.com/leolin310148/ShortcutBadger" + ), + + license( + "EventBus", + "2012-2020", + "Markus Junginger, greenrobot", + OpenSourceLicense.APACHE_2, + "https://github.com/greenrobot/EventBus" + ), + + license( + "android-gif-drawable", + "2013 - present,", + "Karol Wrótniak, Droids on Roids LLC\n", + OpenSourceLicense.MIT, + "https://github.com/koral--/android-gif-drawable" + ), + + license( + "Android Debug Database", + "2019 Amit Shekhar,", + "2011 Android Open Source Project", + OpenSourceLicense.APACHE_2, + "https://github.com/amitshekhariitbhu/Android-Debug-Database" ) - } + ) - override fun getActivityTitle(): CharSequence? { + override fun getActivityTitle(): CharSequence { return getString(R.string.settings_about_licenses_text) } - } From c5eb67271e99390c5f15ec58c8dc9030cb4e7788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 25 Mar 2021 19:38:00 +0100 Subject: [PATCH 046/113] [UI] Fix debugging fragment icon missing. --- app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt index f4b8cafa..017bf619 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt @@ -551,7 +551,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope { if (App.devMode) { bottomSheet += BottomSheetPrimaryItem(false) .withTitle(R.string.menu_debug) - .withIcon(CommunityMaterial.Icon.cmd_android_studio) + .withIcon(CommunityMaterial.Icon.cmd_android_debug_bridge) .withOnClickListener(View.OnClickListener { loadTarget(DRAWER_ITEM_DEBUG) }) } } From e721261e84f11fcad99ba6de1ffe9648d6d64158 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 25 Mar 2021 19:53:11 +0100 Subject: [PATCH 047/113] [UI/Profile] Add showing profile config on long click in drawer. --- .../szczodrzynski/edziennik/MainActivity.kt | 31 +++++-------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt index 017bf619..262c4b39 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt @@ -15,7 +15,6 @@ import android.view.Gravity import android.view.View import android.widget.Toast import androidx.appcompat.app.AppCompatActivity -import androidx.appcompat.widget.PopupMenu import androidx.core.graphics.ColorUtils import androidx.core.view.isVisible import androidx.lifecycle.Observer @@ -55,7 +54,7 @@ import pl.szczodrzynski.edziennik.ui.dialogs.ServerMessageDialog import pl.szczodrzynski.edziennik.ui.dialogs.UpdateAvailableDialog import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog -import pl.szczodrzynski.edziennik.ui.dialogs.profile.ProfileRemoveDialog +import pl.szczodrzynski.edziennik.ui.dialogs.profile.ProfileConfigDialog import pl.szczodrzynski.edziennik.ui.dialogs.sync.SyncViewListDialog import pl.szczodrzynski.edziennik.ui.modules.agenda.AgendaFragment import pl.szczodrzynski.edziennik.ui.modules.announcements.AnnouncementsFragment @@ -389,7 +388,13 @@ class MainActivity : AppCompatActivity(), CoroutineScope { } drawerProfileLongClickListener = { _, profile, _, view -> if (view != null && profile is ProfileDrawerItem) { - showProfileContextMenu(profile, view) + launch { + val appProfile = withContext(Dispatchers.IO) { + App.db.profileDao().getByIdNow(profile.identifier.toInt()) + } ?: return@launch + drawer.close() + ProfileConfigDialog(this@MainActivity, appProfile) + } true } else { @@ -1279,26 +1284,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope { drawer.addProfileSettings(*drawerProfiles.toTypedArray()) } - private fun showProfileContextMenu(profile: IProfile, view: View) { - val profileId = profile.identifier.toInt() - val popupMenu = PopupMenu(this, view) - popupMenu.menu.add(0, 1, 1, R.string.profile_menu_open_settings) - popupMenu.menu.add(0, 2, 2, R.string.profile_menu_remove) - popupMenu.setOnMenuItemClickListener { item -> - if (item.itemId == 1) { - if (profileId != app.profile.id) { - loadProfile(profileId, DRAWER_ITEM_SETTINGS) - return@setOnMenuItemClickListener true - } - loadTarget(DRAWER_ITEM_SETTINGS, null) - } else if (item.itemId == 2) { - ProfileRemoveDialog(this, profileId, profile.name?.getText(this) ?: "?") - } - true - } - popupMenu.show() - } - private val targetPopToHomeList = arrayListOf() private var targetHomeId: Int = -1 override fun onBackPressed() { From db265fa12b247fbf31dfae6cff0a01ab4499482b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 27 Mar 2021 12:53:01 +0100 Subject: [PATCH 048/113] [Gradle] Include Git info in build config. --- app/build.gradle | 4 ++ app/git-info.gradle | 125 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 app/git-info.gradle diff --git a/app/build.gradle b/app/build.gradle index 0e83e107..42960308 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,6 +4,8 @@ apply plugin: 'kotlin-kapt' apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.firebase.crashlytics' +apply from: 'git-info.gradle' + android { compileSdkVersion setup.compileSdk @@ -15,6 +17,8 @@ android { versionCode release.versionCode versionName release.versionName + buildConfigField "java.util.Map", "GIT_INFO", gitInfoMap + multiDexEnabled = true externalNativeBuild { diff --git a/app/git-info.gradle b/app/git-info.gradle new file mode 100644 index 00000000..929d5307 --- /dev/null +++ b/app/git-info.gradle @@ -0,0 +1,125 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-27. + */ + +buildscript { + repositories { + google() + jcenter() + } + dependencies { + classpath "org.eclipse.jgit:org.eclipse.jgit:5.5.+" + } +} + +import org.eclipse.jgit.api.Git +import org.eclipse.jgit.errors.RepositoryNotFoundException +import org.eclipse.jgit.lib.Constants +import org.eclipse.jgit.lib.Ref +import org.eclipse.jgit.lib.Repository +import org.eclipse.jgit.revwalk.RevCommit +import org.eclipse.jgit.revwalk.RevTag +import org.eclipse.jgit.revwalk.RevWalk +import org.eclipse.jgit.storage.file.FileRepositoryBuilder + +private def getGit() { + Repository repo + try { + repo = new FileRepositoryBuilder() + .readEnvironment() + .findGitDir(project.projectDir) + .build() + } catch (IllegalArgumentException | RepositoryNotFoundException ignore) { + def logger = LoggerFactory.getLogger("androidGitVersion") + logger.error("No git repository reachable from ${project.projectDir}") + return results + } + return Git.wrap(repo) +} + +private static def getTags(Repository repo, Git git) { + RevWalk walk = new RevWalk(repo) + def tags = git.tagList().call().findResults { ref -> + def obj = walk.parseAny(ref.getObjectId()) + def name = null + if (obj instanceof RevTag) { + name = obj.getTagName() + } else if (obj instanceof RevCommit) { + name = Repository.shortenRefName(ref.name) + } + [obj.id, name] + } + walk.close() + return tags +} + +private static def getLastTag(Repository repo, Git git, Ref head) { + def tags = getTags(repo, git) + + RevWalk revs = new RevWalk(repo) + revs.markStart(revs.parseCommit(head.getObjectId())) + def revCount = 0 + Collection commitTags = null + for (RevCommit commit : revs) { + def tagsHere = tags.findAll { (it[0] == commit.id) } + if (tagsHere) { + commitTags = tagsHere.stream().map { + [it[0].name, it[1], revCount] + }.toArray() + break + } + revCount++ + } + + return commitTags.last() +} + +private def buildGitInfo() { + Git git = getGit() + Repository repo = git.repository + + def head = repo.findRef(Constants.HEAD).target + + def remotes = git.remoteList().call() + .stream() + .map { + it.name + "(" + it.URIs.stream() + .map { it.rawPath } + .toArray() + .join(", ") + ")" + } + .toArray() + .join("; ") + + def status = git.status().call() + def dirty = status.hasUncommittedChanges() + + def tag = getLastTag(repo, git, head) + def tagName = tag[1] + def tagRevCount = tag[2] + def versionName = tagName.replace("v", "") + + def result = [ + hash : head.objectId.name, + branch : repo.branch, + dirty : dirty, + remotes : remotes, + unstaged : status.uncommittedChanges.join("; "), + tag : tagName, + revCount : tagRevCount, + version : """$tagName-$tagRevCount-g${head.objectId.name.substring(0, 8)}""" + (dirty ? ".dirty" : ""), + versionHuman: """$versionName-${repo.branch.replace("/", "_")}""" + (dirty ? ".dirty" : "") + ] + return result +} + +private static def getMapString(map) { + def hashMap = "new java.util.HashMap() { {\n" + map.each { k, v -> hashMap += """\tput("${k}", "${v}");\n""" } + return hashMap + "} }" +} + +ext { + gitInfo = buildGitInfo() + gitInfoMap = getMapString(gitInfo) +} From 06407ee43985526fc24d8f82ea03edb96f081625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 27 Mar 2021 14:00:06 +0100 Subject: [PATCH 049/113] [Gradle] Add build flavors. --- app/build.gradle | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/app/build.gradle b/app/build.gradle index 42960308..c39adb71 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -18,6 +18,8 @@ android { versionName release.versionName buildConfigField "java.util.Map", "GIT_INFO", gitInfoMap + buildConfigField "long", "BUILD_TIMESTAMP", String.valueOf(System.currentTimeMillis()) + buildConfigField "String", "VERSION_BASE", release.versionName multiDexEnabled = true @@ -27,6 +29,7 @@ android { } } } + buildTypes { applicationVariants.all { variant -> variant.outputs.all { @@ -47,6 +50,19 @@ android { proguardFiles fileTree('proguard').asList().toArray() } } + flavorDimensions "platform" + productFlavors { + main { + versionName gitInfo.versionHuman + } + official {} + play {} + } + variantFilter { variant -> + def flavors = variant.flavors*.name + setIgnore(variant.buildType.name == "debug" && !flavors.contains("main")) + } + defaultConfig { vectorDrawables.useSupportLibrary = true } From 1af65de548acc51e2b2d5d845d3c2e9f9ec66880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 27 Mar 2021 14:01:37 +0100 Subject: [PATCH 050/113] [App] Implement BuildManager. --- .../java/pl/szczodrzynski/edziennik/App.kt | 1 + .../edziennik/utils/managers/BuildManager.kt | 54 +++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/BuildManager.kt diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/App.kt b/app/src/main/java/pl/szczodrzynski/edziennik/App.kt index 0bc6f2e0..43a8b921 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/App.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/App.kt @@ -67,6 +67,7 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope { val eventManager by lazy { EventManager(this) } val permissionManager by lazy { PermissionManager(this) } val attendanceManager by lazy { AttendanceManager(this) } + val buildManager by lazy { BuildManager(this) } val db get() = App.db diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/BuildManager.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/BuildManager.kt new file mode 100644 index 00000000..a05a9491 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/BuildManager.kt @@ -0,0 +1,54 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-27. + */ + +package pl.szczodrzynski.edziennik.utils.managers + +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.BuildConfig +import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.Signing +import pl.szczodrzynski.edziennik.md5 + +class BuildManager(val app: App) { + + val buildFlavor = BuildConfig.FLAVOR + val buildType = BuildConfig.BUILD_TYPE + val buildTimestamp = BuildConfig.BUILD_TIMESTAMP + val isRelease = !BuildConfig.DEBUG + val isDebug = BuildConfig.DEBUG + val isNightly = BuildConfig.VERSION_NAME.contains("nightly") + val isDaily = BuildConfig.VERSION_NAME.contains("daily") + + val gitHash = BuildConfig.GIT_INFO["hash"] + val gitVersion = BuildConfig.GIT_INFO["version"] + val gitBranch = BuildConfig.GIT_INFO["branch"] + val gitUnstaged = BuildConfig.GIT_INFO["unstaged"]?.split("; ") + val gitRevCount = BuildConfig.GIT_INFO["revCount"] + val gitTag = BuildConfig.GIT_INFO["tag"] + val gitIsDirty = BuildConfig.GIT_INFO["dirty"] !== "false" + val gitRemotes = BuildConfig.GIT_INFO["remotes"]?.split("; ") + + val isSigned = Signing.appCertificate.md5() == "d8bab5259fda7d72121fe5db526a3d4d" + + val isPlayRelease = isRelease && buildFlavor == "play" + val isApkRelease = isRelease && buildFlavor == "official" + val isOfficial = isSigned && (isPlayRelease || isApkRelease) + + val versionName = when { + isOfficial -> BuildConfig.VERSION_NAME + ", " + BuildConfig.BUILD_TYPE + isRelease -> "$gitVersion\n$gitBranch" + else -> BuildConfig.VERSION_NAME + } + + val versionBadge = when { + isOfficial && isNightly -> + "Nightly\n" + BuildConfig.VERSION_NAME.substringAfterLast('.') + isOfficial && isDaily -> + "Daily\n" + BuildConfig.VERSION_NAME.substringAfterLast('.') + isDebug -> + "Debug\n" + BuildConfig.VERSION_BASE + !isOfficial -> + "Unofficial\n" + BuildConfig.VERSION_BASE + else -> null + } +} From bf5fb5f6236511b7098f5d7296ba8fe7f3120a90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 27 Mar 2021 14:06:30 +0100 Subject: [PATCH 051/113] [UI] Update main activity badge. --- app/build.gradle | 2 +- .../pl/szczodrzynski/edziennik/MainActivity.kt | 18 +++--------------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index c39adb71..c9751c52 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -19,7 +19,7 @@ android { buildConfigField "java.util.Map", "GIT_INFO", gitInfoMap buildConfigField "long", "BUILD_TIMESTAMP", String.valueOf(System.currentTimeMillis()) - buildConfigField "String", "VERSION_BASE", release.versionName + buildConfigField "String", "VERSION_BASE", "\"${release.versionName}\"" multiDexEnabled = true diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt index de9b5f85..3e953239 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt @@ -302,21 +302,9 @@ class MainActivity : AppCompatActivity(), CoroutineScope { mainSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar) errorSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar) - when { - BuildConfig.VERSION_NAME.contains("nightly") -> { - b.nightlyText.isVisible = true - b.nightlyText.text = "Nightly\n"+BuildConfig.VERSION_NAME.substringAfterLast(".") - } - BuildConfig.VERSION_NAME.contains("daily") -> { - b.nightlyText.isVisible = true - b.nightlyText.text = "Daily\n"+BuildConfig.VERSION_NAME.substringAfterLast(".") - } - BuildConfig.DEBUG -> { - b.nightlyText.isVisible = true - b.nightlyText.text = "Debug\n"+BuildConfig.VERSION_NAME - } - else -> b.nightlyText.isVisible = false - } + val versionBadge = app.buildManager.versionBadge + b.nightlyText.isVisible = versionBadge != null + b.nightlyText.text = versionBadge navLoading = true From 704a55d789539c40573a9b3743d9cbd639959552 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 27 Mar 2021 14:09:38 +0100 Subject: [PATCH 052/113] [UI] Update version info in Settings. --- .../edziennik/ui/modules/settings/SettingsNewFragment.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java index d009cdf1..09625333 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java @@ -43,7 +43,6 @@ import java.util.List; import eu.szkolny.font.SzkolnyFont; import kotlin.Unit; import pl.szczodrzynski.edziennik.App; -import pl.szczodrzynski.edziennik.BuildConfig; import pl.szczodrzynski.edziennik.ExtensionsKt; import pl.szczodrzynski.edziennik.MainActivity; import pl.szczodrzynski.edziennik.R; @@ -1021,7 +1020,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { pref_about_version = new MaterialAboutActionItem.Builder() .text(R.string.settings_about_version_text) - .subText(BuildConfig.VERSION_NAME + ", " + BuildConfig.BUILD_TYPE) + .subText(app.getBuildManager().getVersionName()) .icon(icon(CommunityMaterial.Icon2.cmd_information_outline, iconSizeDp, primaryTextOnPrimaryBg)) .build(); final int[] clickCounter = {0}; From 726a37d5d6fde2570981519eb27c68b98bb0d057 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 27 Mar 2021 14:33:10 +0100 Subject: [PATCH 053/113] [UI] Add build details dialog. --- .../edziennik/utils/managers/BuildManager.kt | 40 +++++++++++++++++-- app/src/main/res/values/strings.xml | 13 ++++++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/BuildManager.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/BuildManager.kt index a05a9491..1b8c2453 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/BuildManager.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/BuildManager.kt @@ -4,10 +4,10 @@ package pl.szczodrzynski.edziennik.utils.managers -import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.BuildConfig +import androidx.appcompat.app.AppCompatActivity +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.Signing -import pl.szczodrzynski.edziennik.md5 class BuildManager(val app: App) { @@ -51,4 +51,38 @@ class BuildManager(val app: App) { "Unofficial\n" + BuildConfig.VERSION_BASE else -> null } + + fun showVersionDialog(activity: AppCompatActivity) { + val yes = activity.getString(R.string.yes) + val no = activity.getString(R.string.no) + + val fields = mapOf( + R.string.build_version to BuildConfig.VERSION_BASE, + R.string.build_official to if (isOfficial) yes else no, + R.string.build_platform to when { + isPlayRelease -> activity.getString(R.string.build_platform_play) + isApkRelease -> activity.getString(R.string.build_platform_apk) + else -> activity.getString(R.string.build_platform_unofficial) + }, + R.string.build_branch to gitBranch, + R.string.build_commit to gitHash?.substring(0, 8), + R.string.build_dirty to if (gitUnstaged?.isEmpty() == true) + "-" + else + "\t" + gitUnstaged?.join("\n\t"), + R.string.build_tag to gitTag, + R.string.build_rev_count to gitRevCount, + R.string.build_remote to gitRemotes?.join("\n") + ) + + val message = fields.map { (key, value) -> + activity.getString(key) + ":\n" + value + }.join("\n\n") + + MaterialAlertDialogBuilder(activity) + .setTitle(R.string.build_details) + .setMessage(message) + .setPositiveButton(R.string.ok, null) + .show() + } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0ea45e49..08c76e90 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1387,4 +1387,17 @@ {cmd-android-studio} Wersja deweloperska \??? Szkoda, opinie innych pomagają mi rozwijać aplikację. + Wersja aplikacji + Wydanie oficjalne + Dystrybucja + Google Play + .APK + Nieoficjalnie (.APK) + Gałąź Git + Identyfikator rewizji + Niezapisane zmiany + Ostatni tag + Rewizje od ostatniego tagu + Repozytorium zdalne + Informacje o kompilacji From 6824960731bfcbebe18a864fc2bc9b8790dd6fad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 27 Mar 2021 16:28:09 +0100 Subject: [PATCH 054/113] [App] Implement basic app validation and related UI. --- app/src/main/AndroidManifest.xml | 1 + .../szczodrzynski/edziennik/MainActivity.kt | 2 + .../szczodrzynski/edziennik/config/Config.kt | 5 + .../ui/modules/base/BuildInvalidActivity.kt | 33 +++++ .../ui/modules/login/LoginActivity.kt | 2 + .../edziennik/utils/managers/BuildManager.kt | 137 +++++++++++++++++- .../res/layout/activity_build_invalid.xml | 65 +++++++++ app/src/main/res/values/strings.xml | 9 ++ 8 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/base/BuildInvalidActivity.kt create mode 100644 app/src/main/res/layout/activity_build_invalid.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6e8fc491..c5bfa07f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -147,6 +147,7 @@ + + + + + + + + + + + + + + + + +