diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt index 76719287..53803650 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt @@ -14,6 +14,7 @@ import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher import pl.szczodrzynski.navlib.R import pl.szczodrzynski.navlib.crc16 import pl.szczodrzynski.navlib.getColorFromRes +import java.util.* fun List.byId(id: Long) = firstOrNull { it.id == id } fun List.byNameFirstLast(nameFirstLast: String) = firstOrNull { it.name + " " + it.surname == nameFirstLast } @@ -87,3 +88,52 @@ fun Activity.isStoragePermissionGranted(): Boolean { true } } + +fun Activity.setLanguage(language: String) { + val locale = Locale(language.toLowerCase(Locale.ROOT)) + val configuration = resources.configuration + Locale.setDefault(locale) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + configuration.setLocale(locale) + } + configuration.locale = locale + resources.updateConfiguration(configuration, resources.displayMetrics) + baseContext.resources.updateConfiguration(configuration, baseContext.resources.displayMetrics) +} + +/* + Code copied from android-28/java.util.Locale.initDefault() + */ +fun initDefaultLocale() { + run { + // user.locale gets priority + /*val languageTag: String? = System.getProperty("user.locale", "") + if (languageTag.isNotNullNorEmpty()) { + return@run Locale(languageTag) + }*/ + + // user.locale is empty + val language: String? = System.getProperty("user.language", "pl") + val region: String? = System.getProperty("user.region") + val country: String? + val variant: String? + // for compatibility, check for old user.region property + if (region != null) { + // region can be of form country, country_variant, or _variant + val i = region.indexOf('_') + if (i >= 0) { + country = region.substring(0, i) + variant = region.substring(i + 1) + } else { + country = region + variant = "" + } + } else { + country = System.getProperty("user.country", "") + variant = System.getProperty("user.variant", "") + } + return@run Locale(language) + }.let { + Locale.setDefault(it) + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt index e617b152..1cc5ca19 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt @@ -236,6 +236,10 @@ class MainActivity : AppCompatActivity() { setTheme(Themes.appTheme) + app.appConfig.language?.let { + setLanguage(it) + } + setContentView(b.root) navLoading = true 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 932e89eb..76fb23c1 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 @@ -38,28 +38,27 @@ import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.Map; import pl.szczodrzynski.edziennik.App; import pl.szczodrzynski.edziennik.BuildConfig; +import pl.szczodrzynski.edziennik.MainActivity; import pl.szczodrzynski.edziennik.Notifier; import pl.szczodrzynski.edziennik.R; -import pl.szczodrzynski.edziennik.MainActivity; import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore; -import pl.szczodrzynski.edziennik.ui.modules.webpush.WebPushConfigActivity; -import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog; -import pl.szczodrzynski.edziennik.utils.models.Endpoint; -import pl.szczodrzynski.edziennik.utils.models.Time; import pl.szczodrzynski.edziennik.network.NetworkUtils; import pl.szczodrzynski.edziennik.network.ServerRequest; import pl.szczodrzynski.edziennik.receivers.BootReceiver; import pl.szczodrzynski.edziennik.sync.SyncJob; +import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog; import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment; +import pl.szczodrzynski.edziennik.ui.modules.webpush.WebPushConfigActivity; import pl.szczodrzynski.edziennik.utils.Themes; import pl.szczodrzynski.edziennik.utils.Utils; +import pl.szczodrzynski.edziennik.utils.models.Time; import static android.app.Activity.RESULT_OK; import static pl.szczodrzynski.edziennik.App.APP_URL; +import static pl.szczodrzynski.edziennik.ExtensionsKt.initDefaultLocale; import static pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile.REGISTRATION_DISABLED; import static pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile.REGISTRATION_ENABLED; import static pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile.YEAR_1_AVG_2_AVG; @@ -81,8 +80,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { 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_SYNC_CUSTOMIZE = 4; - private static final int CARD_ABOUT = 5; + private static final int CARD_ABOUT = 4; private int iconColor = Color.WHITE; private int primaryTextOnPrimaryBg = -1; private int secondaryTextOnPrimaryBg = -1; @@ -1081,136 +1079,6 @@ public class SettingsNewFragment extends MaterialAboutFragment { return items; } - /* _____ ______ _ _ _ - / ____| | ____| | | (_) | | - | (___ _ _ _ __ ___ | |__ _ __ __| |_ __ ___ _ _ __ | |_ ___ - \___ \| | | | '_ \ / __| | __| | '_ \ / _` | '_ \ / _ \| | '_ \| __/ __| - ____) | |_| | | | | (__ | |____| | | | (_| | |_) | (_) | | | | | |_\__ \ - |_____/ \__, |_| |_|\___| |______|_| |_|\__,_| .__/ \___/|_|_| |_|\__|___/ - __/ | | | - |___/ |*/ - private String getEndpointTitle(String name) { - int stringRes = -1; - switch (name) { - case "Classrooms": - stringRes = R.string.settings_sync_customize_endpoint_classrooms; - break; - case "Timetables": - case "Timetable": - stringRes = R.string.settings_sync_customize_endpoint_timetable; - break; - case "Substitutions": - stringRes = R.string.settings_sync_customize_endpoint_substitutions; - break; - case "Grades": - stringRes = R.string.settings_sync_customize_endpoint_grades; - break; - case "PointGrades": - stringRes = R.string.settings_sync_customize_endpoint_point_grades; - break; - case "Events": - stringRes = R.string.settings_sync_customize_endpoint_events; - break; - case "Homework": - stringRes = R.string.settings_sync_customize_endpoint_homework; - break; - case "LuckyNumber": - case "LuckyNumbers": - stringRes = R.string.settings_sync_customize_endpoint_lucky_numbers; - break; - case "Notices": - stringRes = R.string.settings_sync_customize_endpoint_notices; - break; - case "Attendance": - stringRes = R.string.settings_sync_customize_endpoint_attendance; - break; - case "Announcements": - stringRes = R.string.settings_sync_customize_endpoint_announcements; - break; - case "PtMeetings": - stringRes = R.string.settings_sync_customize_endpoint_pt_meetings; - break; - case "TeacherFreeDays": - stringRes = R.string.settings_sync_customize_endpoint_teacher_free_days; - break; - case "SchoolFreeDays": - stringRes = R.string.settings_sync_customize_endpoint_school_free_days; - break; - case "ClassFreeDays": - stringRes = R.string.settings_sync_customize_endpoint_class_free_days; - break; - case "MessagesInbox": - stringRes = R.string.settings_sync_customize_endpoint_messages_inbox; - break; - case "MessagesOutbox": - stringRes = R.string.settings_sync_customize_endpoint_messages_outbox; - break; - } - if (stringRes == -1) - return name; - else - return getString(stringRes); - } - private MaterialAboutSwitchItem getEndpointSwitch(String name, Endpoint endpoint) { - return new MaterialAboutSwitchItem( - getEndpointTitle(name), - endpoint.onlyFullSync ? getString(R.string.settings_sync_customize_full_sync_only) : null, - null - ) - .setChecked(endpoint.enabled) - .setOnChangeAction((isChecked, tag) -> { - endpoint.enabled = isChecked; - boolean changed = isChecked ^ endpoint.defaultActive; - if (!changed) { - if (app.profile.getChangedEndpoints() != null) { - app.profile.getChangedEndpoints().remove(name); - } - } - else { - if (app.profile.getChangedEndpoints() == null) - app.profile.setChangedEndpoints(new ArrayList<>()); - app.profile.getChangedEndpoints().add(name); - } - app.profileSaveAsync(); - return true; - }); - } - private Map configurableEndpoints = null; - private ArrayList getSyncCustomizeCard(boolean expandedOnly) { - ArrayList items = new ArrayList<>(); - if (!expandedOnly) { - items.add( - new MaterialAboutActionItem( - null, - getString(R.string.settings_sync_customize_help_subtext), - null - ) - ); - - if (app.profile.getChangedEndpoints() != null) { - for (String changedEndpoint : app.profile.getChangedEndpoints()) { - Endpoint endpoint = configurableEndpoints.get(changedEndpoint); - if (endpoint == null) - continue; - items.add(getEndpointSwitch(changedEndpoint, endpoint)); - } - } - - items.add(getMoreItem(() -> addCardItems(CARD_SYNC_CUSTOMIZE, getSyncCustomizeCard(true)))); - } - else { - for (String endpointName: configurableEndpoints.keySet()) { - if (app.profile.getChangedEndpoints() != null && app.profile.getChangedEndpoints().contains(endpointName)) - continue; - Endpoint endpoint = configurableEndpoints.get(endpointName); - if (endpoint == null) - continue; - items.add(getEndpointSwitch(endpointName, endpoint)); - } - } - return items; - } - /* _ _ /\ | | | | / \ | |__ ___ _ _| |_ @@ -1223,117 +1091,152 @@ public class SettingsNewFragment extends MaterialAboutFragment { secondaryTextOnPrimaryBg = 0xd0ffffff;//activity.getResources().getColor(R.color.secondaryTextLight); ArrayList items = new ArrayList<>(); - 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()); + if (!expandedOnly) { + 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) - .color(IconicsColor.colorInt(primaryTextOnPrimaryBg)) - .size(IconicsSize.dp(iconSizeDp))) - .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); + 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) + .color(IconicsColor.colorInt(primaryTextOnPrimaryBg)) + .size(IconicsSize.dp(iconSizeDp))) + .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) - .textColor(primaryTextOnPrimaryBg) - .subTextColor(secondaryTextOnPrimaryBg) - .icon(new IconicsDrawable(activity) - .icon(CommunityMaterial.Icon2.cmd_shield_half_full) - .color(IconicsColor.colorInt(primaryTextOnPrimaryBg)) - .size(IconicsSize.dp(iconSizeDp))) - .setOnClickAction(ConvenienceBuilder.createWebsiteOnClickAction(activity, Uri.parse("https://szkolny.eu/privacy-policy"))) - .build()); + 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_half_full) + .color(IconicsColor.colorInt(primaryTextOnPrimaryBg)) + .size(IconicsSize.dp(iconSizeDp))) + .setOnClickAction(ConvenienceBuilder.createWebsiteOnClickAction(activity, Uri.parse("https://szkolny.eu/privacy-policy"))) + .build()); - 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(CommunityMaterial.Icon.cmd_discord) - .color(IconicsColor.colorInt(primaryTextOnPrimaryBg)) - .size(IconicsSize.dp(iconSizeDp))) - .setOnClickAction(ConvenienceBuilder.createWebsiteOnClickAction(activity, Uri.parse("https://discord.gg/n9e8pWr"))) - .build()); + 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(CommunityMaterial.Icon.cmd_discord) + .color(IconicsColor.colorInt(primaryTextOnPrimaryBg)) + .size(IconicsSize.dp(iconSizeDp))) + .setOnClickAction(ConvenienceBuilder.createWebsiteOnClickAction(activity, Uri.parse("https://discord.gg/n9e8pWr"))) + .build()); - 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)) - .size(IconicsSize.dp(iconSizeDp))) - .setOnClickAction(() -> { - //open browser or intent here - NetworkUtils net = new NetworkUtils(app); - if (!net.isOnline()) - { + 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) + .color(IconicsColor.colorInt(primaryTextOnPrimaryBg)) + .size(IconicsSize.dp(iconSizeDp))) + .setOnClickAction(() -> { new MaterialDialog.Builder(activity) - .title(R.string.you_are_offline_title) - .content(R.string.you_are_offline_text) - .positiveText(R.string.ok) + .title(getString(R.string.settings_about_language_dialog_title)) + .content(getString(R.string.settings_about_language_dialog_text)) + .items(getString(R.string.language_system), getString(R.string.language_polish), getString(R.string.language_english)) + .itemsCallbackSingleChoice(app.appConfig.language == null ? 0 : app.appConfig.language.equals("pl") ? 1 : 2, (dialog, itemView, which, text) -> { + switch (which) { + case 0: + app.appConfig.language = null; + initDefaultLocale(); + break; + case 1: + app.appConfig.language = "pl"; + break; + case 2: + app.appConfig.language = "en"; + break; + } + app.saveConfig("language"); + activity.recreate(MainActivity.DRAWER_ITEM_SETTINGS); + return true; + }) .show(); - } - else - { - BootReceiver br = new BootReceiver(); - Intent i = new Intent(); - i.putExtra("UserChecked", true); - br.onReceive(getContext(), i); - } - }) - .build()); + }) + .build()); - 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)) - .size(IconicsSize.dp(iconSizeDp))) - .setOnClickAction(() -> new ChangelogDialog().show(getActivity().getSupportFragmentManager(), "whats_new")) - .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) + .textColor(primaryTextOnPrimaryBg) + .subTextColor(secondaryTextOnPrimaryBg) + .icon(new IconicsDrawable(activity) + .icon(CommunityMaterial.Icon2.cmd_update) + .color(IconicsColor.colorInt(primaryTextOnPrimaryBg)) + .size(IconicsSize.dp(iconSizeDp))) + .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 { + BootReceiver br = new BootReceiver(); + Intent i = new Intent(); + i.putExtra("UserChecked", true); + br.onReceive(getContext(), i); + } + }) + .build()); - 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)) - .size(IconicsSize.dp(iconSizeDp))) - .setOnClickAction(() -> { - Intent intent = new Intent(activity, SettingsLicenseActivity.class); - startActivity(intent); - }) - .build()); + 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)) + .size(IconicsSize.dp(iconSizeDp))) + .setOnClickAction(() -> new ChangelogDialog().show(getActivity().getSupportFragmentManager(), "whats_new")) + .build()); + + 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)) + .size(IconicsSize.dp(iconSizeDp))) + .setOnClickAction(() -> { + Intent intent = new Intent(activity, SettingsLicenseActivity.class); + startActivity(intent); + }) + .build()); /*items.add(new MaterialAboutActionItem.Builder() .text(R.string.settings_about_intro_text) @@ -1357,20 +1260,21 @@ public class SettingsNewFragment extends MaterialAboutFragment { }) .build());*/ - if (App.devMode) { - 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) - .color(IconicsColor.colorInt(primaryTextOnPrimaryBg)) - .size(IconicsSize.dp(iconSizeDp))) - .setOnClickAction(() -> { - throw new RuntimeException("MANUAL CRASH"); - }) - .build()); + if (App.devMode) { + 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) + .color(IconicsColor.colorInt(primaryTextOnPrimaryBg)) + .size(IconicsSize.dp(iconSizeDp))) + .setOnClickAction(() -> { + throw new RuntimeException("MANUAL CRASH"); + }) + .build()); + } } return items; } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/AppConfig.java b/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/AppConfig.java index 2aefccf0..b2d104e2 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/AppConfig.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/AppConfig.java @@ -2,6 +2,8 @@ package pl.szczodrzynski.edziennik.utils.models; import android.util.Pair; +import androidx.annotation.Nullable; + import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -110,4 +112,7 @@ public class AppConfig { public long appRateSnackbarTime = 0; public int mobidziennikOldMessages = -1; + + @Nullable + public String language = null; } diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index a200e659..5e3b12c3 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -856,4 +856,14 @@ Getting school free days Show teacher absences in Agenda Mark everything as read + App language + "English " + Change app language + Notice. This feature may not work on some devices or in some parts of the app. + Discord server + Join our Discord community! + Use system language + (child) + (parent) + Syncing... diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4179f64c..d76e8828 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -912,4 +912,11 @@ Nieobecni nauczyciele Pobieranie komentarzy ocen Pokazuj nieobecności nauczycieli w Terminarzu + Język aplikacji + Polski + Zmień język aplikacji + Uwaga. Ta opcja może nie działać na niektórych urządzeniach oraz w niektórych fragmentach aplikacji. + Według systemu + Polski + English