diff --git a/course/app/build.gradle b/course/app/build.gradle index 8d547dc..d06a92a 100644 --- a/course/app/build.gradle +++ b/course/app/build.gradle @@ -2,6 +2,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-kapt' apply plugin: "androidx.navigation.safeargs.kotlin" +apply plugin: 'com.mikepenz.aboutlibraries.plugin' def apikeyPropertiesFile = rootProject.file("apikey.properties") def apikeyProperties = new Properties() @@ -50,6 +51,7 @@ dependencies { kapt "androidx.room:room-compiler:$rootProject.roomVersion" implementation fileTree(dir: 'libs', include: ['*.jar']) 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.6.0' implementation "androidx.fragment:fragment-ktx:1.3.5" @@ -77,4 +79,8 @@ dependencies { implementation 'com.github.chrisbanes:PhotoView:2.3.0' implementation 'com.github.MikeOrtiz:TouchImageView:3.0.1' + + implementation "com.mikepenz:aboutlibraries:${latestAboutLibsRelease}" + implementation "com.mikepenz:aboutlibraries-core:${latestAboutLibsRelease}" + } diff --git a/course/app/src/main/java/com/txwstudio/app/timetable/HomeViewPagerFragment.kt b/course/app/src/main/java/com/txwstudio/app/timetable/HomeViewPagerFragment.kt index b040e18..80915cb 100644 --- a/course/app/src/main/java/com/txwstudio/app/timetable/HomeViewPagerFragment.kt +++ b/course/app/src/main/java/com/txwstudio/app/timetable/HomeViewPagerFragment.kt @@ -1,5 +1,6 @@ package com.txwstudio.app.timetable +import android.app.Activity import android.content.ActivityNotFoundException import android.content.Intent import android.content.SharedPreferences @@ -103,7 +104,13 @@ class HomeViewPagerFragment : Fragment() { return true } R.id.menuSettings -> { - startActivity(Intent(requireContext(), PreferenceActivity::class.java)) + val a = HomeViewPagerFragmentDirections.actionHomeViewPagerFragmentToPreferenceActivity() + findNavController().navigate(a) + /** + * Maybe use startActivityForResult + * {@link #getPrefValue} + * */ +// startActivity(Intent(requireContext(), PreferenceActivity::class.java)) return true } else -> super.onOptionsItemSelected(item) diff --git a/course/app/src/main/java/com/txwstudio/app/timetable/Ui/activity/PreferenceActivity.kt b/course/app/src/main/java/com/txwstudio/app/timetable/Ui/activity/PreferenceActivity.kt index a89360f..2b67273 100644 --- a/course/app/src/main/java/com/txwstudio/app/timetable/Ui/activity/PreferenceActivity.kt +++ b/course/app/src/main/java/com/txwstudio/app/timetable/Ui/activity/PreferenceActivity.kt @@ -1,57 +1,83 @@ package com.txwstudio.app.timetable.ui.activity import android.os.Bundle -import android.view.MenuItem import androidx.appcompat.app.AppCompatActivity import androidx.databinding.DataBindingUtil +import androidx.fragment.app.FragmentTransaction import androidx.fragment.app.commit import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import com.txwstudio.app.timetable.R import com.txwstudio.app.timetable.databinding.ActivityPreferenceBinding +import com.txwstudio.app.timetable.ui.preferences.PreferenceFragment + +private const val TITLE_TAG = "settingsActivityTitle" class PreferenceActivity : AppCompatActivity(), - PreferenceFragmentCompat.OnPreferenceStartFragmentCallback { + PreferenceFragmentCompat.OnPreferenceStartFragmentCallback { private lateinit var binding: ActivityPreferenceBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = DataBindingUtil.setContentView(this, R.layout.activity_preference) + setSupportActionBar(binding.toolbarSettingsAct) supportActionBar?.setDisplayHomeAsUpEnabled(true) - } + binding.toolbarSettingsAct.setNavigationOnClickListener { + onBackPressed() + } + + if (savedInstanceState == null) { + supportFragmentManager.beginTransaction() + .replace(R.id.fragment_container_view, PreferenceFragment()) + .commit() + } else { + title = savedInstanceState.getCharSequence(TITLE_TAG) + } - override fun onOptionsItemSelected(item: MenuItem): Boolean { - return when (item.itemId) { - android.R.id.home -> { - finish() - true + supportFragmentManager.addOnBackStackChangedListener { + if (supportFragmentManager.backStackEntryCount == 0) { + setTitle(R.string.title_activity_settings) } - else -> super.onOptionsItemSelected(item) } } - override fun onPreferenceStartFragment(caller: PreferenceFragmentCompat?, pref: Preference): Boolean { + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + // Save current activity title so we can set it again after a configuration change + outState.putCharSequence(TITLE_TAG, title) + } + + override fun onSupportNavigateUp(): Boolean { + if (supportFragmentManager.popBackStackImmediate()) { + return true + } + return super.onSupportNavigateUp() + } + + override fun onPreferenceStartFragment( + caller: PreferenceFragmentCompat, + pref: Preference + ): Boolean { // Instantiate the new Fragment val args = pref.extras val fragment = supportFragmentManager.fragmentFactory.instantiate( - classLoader, - pref.fragment) - fragment.arguments = args - fragment.setTargetFragment(caller, 0) + classLoader, + pref.fragment + ).apply { + arguments = args + // setTargetFragment(caller, 0) // deprecated in java + } // Replace the existing Fragment with the new Fragment supportFragmentManager.commit { - setCustomAnimations( - R.anim.fade_in, - R.anim.fade_out, - R.anim.fade_in, - R.anim.fade_out - ) + setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) replace(R.id.fragment_container_view, fragment) addToBackStack(null) } + binding.appBarLayoutSettingsAct.setExpanded(true, true) + title = pref.title return true } } \ No newline at end of file diff --git a/course/app/src/main/java/com/txwstudio/app/timetable/Ui/preferences/PreferenceFragment.kt b/course/app/src/main/java/com/txwstudio/app/timetable/Ui/preferences/PreferenceFragment.kt index 77301bb..44dc031 100644 --- a/course/app/src/main/java/com/txwstudio/app/timetable/Ui/preferences/PreferenceFragment.kt +++ b/course/app/src/main/java/com/txwstudio/app/timetable/Ui/preferences/PreferenceFragment.kt @@ -1,6 +1,7 @@ package com.txwstudio.app.timetable.ui.preferences import android.app.Activity +import android.content.Context import android.content.Intent import android.content.SharedPreferences import android.content.pm.ShortcutInfo @@ -9,10 +10,11 @@ import android.graphics.drawable.Icon import android.net.Uri import android.os.Build import android.os.Bundle +import android.view.View import android.widget.Toast +import androidx.activity.result.contract.ActivityResultContract import androidx.appcompat.app.AppCompatDelegate import androidx.browser.customtabs.CustomTabsIntent -import androidx.preference.EditTextPreference import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceManager @@ -27,8 +29,7 @@ private const val PREFERENCE_CALENDAR_PICKER = "pref_schoolCalendarPicker" private const val PREFERENCE_MAP_CAL_HELPER = "pref_mapCalHelper" const val PREFERENCE_WEEKEND_COL = "pref_weekendCol" const val PREFERENCE_WEEKDAY_LENGTH_LONG = "pref_weekdayLengthLong" -private const val PREFERENCE_TEACHER_COL = "pref_teacherCol" -private const val PREFERENCE_CHANGELOG = "pref_changelog" +private const val PREFERENCE_BUG_REPORT = "pref_bugReport" const val PREFERENCE_NAME_MAP_REQUEST = "schoolMapPath" const val PREFERENCE_NAME_CALENDAR_REQUEST = "schoolCalendarPath" @@ -40,15 +41,52 @@ private const val REQUEST_CODE_CALENDAR = 1 private const val BUG_REPORT_LINK = "http://bit.ly/timetableFeedback" class PreferenceFragment : PreferenceFragmentCompat(), - Preference.OnPreferenceClickListener, SharedPreferences.OnSharedPreferenceChangeListener { + Preference.OnPreferenceClickListener, SharedPreferences.OnSharedPreferenceChangeListener { private lateinit var prefManager: SharedPreferences - private lateinit var editTextPreference: EditTextPreference - override fun onActivityCreated(savedInstanceState: Bundle?) { - super.onActivityCreated(savedInstanceState) + private val getMapContract = registerForActivityResult(MyContract()) { documentUri -> + if (documentUri == null) { + Toast.makeText(requireActivity(), R.string.fileReadErrorMsg, Toast.LENGTH_SHORT).show() + } else { + // Persist the permission across restarts. + requireActivity().contentResolver.takePersistableUriPermission( + documentUri, + Intent.FLAG_GRANT_READ_URI_PERMISSION + ) + + // Save the document to [SharedPreferences]. + prefManager.edit().putString( + PREFERENCE_NAME_MAP_REQUEST, + documentUri.toString() + ).commit() + } + } + + private val getCalendarContract = registerForActivityResult(MyContract()) { documentUri -> + if (documentUri == null) { + Toast.makeText(requireActivity(), R.string.fileReadErrorMsg, Toast.LENGTH_SHORT).show() + } else { + // Persist the permission across restarts. + requireActivity().contentResolver.takePersistableUriPermission( + documentUri, + Intent.FLAG_GRANT_READ_URI_PERMISSION + ) + + createShortcut(documentUri) + + // Save the document to [SharedPreferences]. + prefManager.edit().putString( + PREFERENCE_NAME_CALENDAR_REQUEST, + documentUri.toString() + ).commit() + } + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) prefManager = PreferenceManager.getDefaultSharedPreferences(requireContext()) - setInitSummary() +// PreferenceManager.setDefaultValues(requireContext(), R.xml.preferences, false) } override fun onResume() { @@ -63,6 +101,8 @@ class PreferenceFragment : PreferenceFragmentCompat(), /** * Handle file section, invoked by showPicker(). + * + * @deprecated Switched to ActivityResultContract. Will be deleted soon. * */ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) @@ -76,7 +116,7 @@ class PreferenceFragment : PreferenceFragmentCompat(), } override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - addPreferencesFromResource(R.xml.preferences) + setPreferencesFromResource(R.xml.preferences, rootKey) } override fun onPreferenceClick(preference: Preference?): Boolean { @@ -85,11 +125,10 @@ class PreferenceFragment : PreferenceFragmentCompat(), override fun onPreferenceTreeClick(preference: Preference?): Boolean { when (preference?.key) { - PREFERENCE_MAP_PICKER -> showPicker(REQUEST_CODE_MAP) - PREFERENCE_CALENDAR_PICKER -> showPicker(REQUEST_CODE_CALENDAR) + PREFERENCE_MAP_PICKER -> getMapContract.launch(REQUEST_CODE_MAP) + PREFERENCE_CALENDAR_PICKER -> getCalendarContract.launch(REQUEST_CODE_CALENDAR) PREFERENCE_MAP_CAL_HELPER -> showDialog(PREFERENCE_MAP_CAL_HELPER) - - "pref_bugReport" -> { + PREFERENCE_BUG_REPORT -> { val customTabsIntent = CustomTabsIntent.Builder().build() customTabsIntent.launchUrl(requireContext(), Uri.parse(BUG_REPORT_LINK)) } @@ -99,11 +138,6 @@ class PreferenceFragment : PreferenceFragmentCompat(), override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { when (key) { - PREFERENCE_TABLE_TITLE -> { - editTextPreference.summary = - sharedPreferences?.getString(PREFERENCE_TABLE_TITLE, - java.lang.String.valueOf(R.string.settings_timetableTitleSummary)) - } PREFERENCE_THEME -> { val value = sharedPreferences?.getString(PREFERENCE_THEME, "-1")?.toInt() AppCompatDelegate.setDefaultNightMode(value!!) @@ -111,18 +145,10 @@ class PreferenceFragment : PreferenceFragmentCompat(), } } - /** - * Set summary when open preference screen. - * */ - private fun setInitSummary() { - editTextPreference = findPreference(PREFERENCE_TABLE_TITLE)!! - - editTextPreference.summary = prefManager.getString(PREFERENCE_TABLE_TITLE, - getString(R.string.settings_timetableTitleDefaultValue)) - } - /** * Start an activity for picking file + * + * @deprecated Switched to ActivityResultContract. Will be deleted soon. * */ private fun showPicker(requestCode: Int) { val intent = Intent(Intent.ACTION_OPEN_DOCUMENT) @@ -162,6 +188,8 @@ class PreferenceFragment : PreferenceFragmentCompat(), * * @param requestCode Receive code and decide which preference to write. * @param data File uri + * + * @deprecated Switched to ActivityResultContract. Will be deleted soon. */ private fun handleSelectedFile(requestCode: Int, data: Intent) { val prefName = when (requestCode) { @@ -185,8 +213,6 @@ class PreferenceFragment : PreferenceFragmentCompat(), requireActivity().contentResolver.takePersistableUriPermission(fileUri!!, takeFlags) val filePath = fileUri.toString() - /**Old method, remove soon. */ -// String filePath = Util.getPath(getContext(), fileUri); val prefs = PreferenceManager.getDefaultSharedPreferences(requireContext()) val editor = prefs.edit() editor.putString(prefName, filePath) @@ -199,6 +225,8 @@ class PreferenceFragment : PreferenceFragmentCompat(), /** * Create shortcut it user set calendar path. + * + * @deprecated Switched to ActivityResultContract. Will be deleted soon. * */ private fun createShortcut(data: Intent) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { @@ -216,4 +244,50 @@ class PreferenceFragment : PreferenceFragmentCompat(), shortcutManager.dynamicShortcuts = Arrays.asList(shortcut) } } + + /** + * Create shortcut if user set calendar path. + */ + private fun createShortcut(documentUri: Uri) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { + val shortcutManager = requireContext().getSystemService(ShortcutManager::class.java) + val shortcut = ShortcutInfo.Builder(context, "calendarShortcut") + .setShortLabel(getString(R.string.menuCalendar)) + .setLongLabel(getString(R.string.menuCalendar)) + .setIcon(Icon.createWithResource(context, R.mipmap.ic_event_note)) + .setIntent( + Intent(Intent.ACTION_VIEW) + .setDataAndType(documentUri, "application/pdf") + .setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY) + .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + ) + .build() + shortcutManager.dynamicShortcuts = listOf(shortcut) + } + } +} + +/** + * For picking up file. + * */ +class MyContract : ActivityResultContract() { + + override fun createIntent(context: Context, input: Int?): Intent { + return Intent(Intent.ACTION_OPEN_DOCUMENT).apply { + type = when (input) { + REQUEST_CODE_MAP -> "image/*" + REQUEST_CODE_CALENDAR -> "application/pdf" + else -> "image/*" + } + putExtra(Intent.EXTRA_LOCAL_ONLY, true) + } + } + + override fun parseResult(resultCode: Int, intent: Intent?): Uri? { + if (resultCode != Activity.RESULT_OK) { + return null + } + return intent?.data + } + } \ No newline at end of file diff --git a/course/app/src/main/java/com/txwstudio/app/timetable/ui/preferences/PreferencesAboutFragment.kt b/course/app/src/main/java/com/txwstudio/app/timetable/ui/preferences/PreferencesAboutFragment.kt index 0971c1c..b94ec24 100644 --- a/course/app/src/main/java/com/txwstudio/app/timetable/ui/preferences/PreferencesAboutFragment.kt +++ b/course/app/src/main/java/com/txwstudio/app/timetable/ui/preferences/PreferencesAboutFragment.kt @@ -4,9 +4,14 @@ import android.content.SharedPreferences import android.net.Uri import android.os.Bundle import androidx.browser.customtabs.CustomTabsIntent +import androidx.fragment.app.FragmentTransaction +import androidx.fragment.app.commit +import com.mikepenz.aboutlibraries.LibsBuilder import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat +import com.mikepenz.aboutlibraries.Libs import com.txwstudio.app.timetable.R +import com.txwstudio.app.timetable.BuildConfig private const val PREFERENCE_ABOUT_VERSION = "prefAbout_version" private const val PREFERENCE_ABOUT_CHANGELOG = "prefAbout_changelog" @@ -23,7 +28,9 @@ class PreferencesAboutFragment : PreferenceFragmentCompat(), Preference.OnPreferenceClickListener, SharedPreferences.OnSharedPreferenceChangeListener { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - addPreferencesFromResource(R.xml.preferences_about) + setPreferencesFromResource(R.xml.preferences_about, rootKey) + + findPreference(PREFERENCE_ABOUT_VERSION)?.summary = BuildConfig.VERSION_NAME } override fun onPreferenceClick(preference: Preference?): Boolean { @@ -34,7 +41,19 @@ class PreferencesAboutFragment : PreferenceFragmentCompat(), val customTabsIntent = CustomTabsIntent.Builder().build() when (preference?.key) { PREFERENCE_ABOUT_CHANGELOG -> customTabsIntent.launchUrl(requireContext(), Uri.parse(CHANGELOG_LINK)) - PREFERENCE_ABOUT_OPEN_SOURCE -> customTabsIntent.launchUrl(requireContext(), Uri.parse(OPEN_SOURCE_LINK)) + PREFERENCE_ABOUT_OPEN_SOURCE -> { + val fragment = LibsBuilder() + .withFields(R.string::class.java.fields) // in some cases it may be needed to provide the R class, if it can not be automatically resolved + .withLibraryModification("aboutlibraries", Libs.LibraryFields.LIBRARY_NAME, "_AboutLibraries") // optionally apply modifications for library information + .supportFragment() + requireActivity().supportFragmentManager.commit { + setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) + replace(R.id.fragment_container_view, fragment) + setReorderingAllowed(true) + addToBackStack("name") + } + + } PREFERENCE_ABOUT_OFFICIAL_SITE -> customTabsIntent.launchUrl(requireContext(), Uri.parse(OFFICIAL_SITE_LINK)) PREFERENCE_ABOUT_GITHUB -> customTabsIntent.launchUrl(requireContext(), Uri.parse(GITHUB_LINK)) } diff --git a/course/app/src/main/res/layout/activity_preference.xml b/course/app/src/main/res/layout/activity_preference.xml index df718d7..981a497 100644 --- a/course/app/src/main/res/layout/activity_preference.xml +++ b/course/app/src/main/res/layout/activity_preference.xml @@ -2,8 +2,7 @@ - - + + app:layout_constraintTop_toTopOf="parent"> + android:layout_height="?attr/actionBarSize" + app:layout_scrollFlags="scroll|enterAlways" /> diff --git a/course/app/src/main/res/navigation/nav.xml b/course/app/src/main/res/navigation/nav.xml index 692b92d..4ac469f 100644 --- a/course/app/src/main/res/navigation/nav.xml +++ b/course/app/src/main/res/navigation/nav.xml @@ -33,6 +33,9 @@ app:exitAnim="@anim/fragment_open_exit" app:popEnterAnim="@anim/fragment_close_enter" app:popExitAnim="@anim/fragment_close_exit" /> + + \ No newline at end of file diff --git a/course/app/src/main/res/values-en-rUS/strings.xml b/course/app/src/main/res/values-en-rUS/strings.xml index 6e406dc..a26b3cc 100644 --- a/course/app/src/main/res/values-en-rUS/strings.xml +++ b/course/app/src/main/res/values-en-rUS/strings.xml @@ -9,11 +9,9 @@ Map Table Name My Timetable - Version 2.1 Name to show on the main screen Bug Report or feature request. Contact Developers - About General Campus Map Support JPG and PNG @@ -77,4 +75,6 @@ No class today The widget is still in beta No class today. + Others + About \ No newline at end of file diff --git a/course/app/src/main/res/values/strings.xml b/course/app/src/main/res/values/strings.xml index 8d6a19e..570c1af 100644 --- a/course/app/src/main/res/values/strings.xml +++ b/course/app/src/main/res/values/strings.xml @@ -53,7 +53,7 @@ 真的 假的 - + 一般 課表名稱 我的課表 @@ -81,36 +81,37 @@ 顯示完整星期名稱 例如:「星期一」 - 關於 + 其他 聯繫作者 Bug 回報、功能請求 - 版本 2.1 - Made with ❤ in Taiwan - + 關於 + Made with ❤ in Taiwan + - + 版本 - v2.1-release 更新日誌 開放原始碼授權 - + 今天沒課 小工具為測試版 - + 未知錯誤,請在試一次 + - - [設定] -> [自訂學校地圖] 選擇你的圖片 - + + [設定] -> [自訂學校地圖] 選擇你的圖片 + - + 開啟 PDF 使用 找不到可開 PDF 的程式,建議安裝 Google 雲端硬碟 PDF 可能移位了,找不到QQ + 確認 diff --git a/course/app/src/main/res/xml/preferences.xml b/course/app/src/main/res/xml/preferences.xml index 939bf96..b341719 100644 --- a/course/app/src/main/res/xml/preferences.xml +++ b/course/app/src/main/res/xml/preferences.xml @@ -1,5 +1,5 @@ - @@ -10,7 +10,8 @@ android:key="tableTitle_Pref" android:selectAllOnFocus="true" android:singleLine="true" - android:title="@string/settings_timetableTitle" /> + android:title="@string/settings_timetableTitle" + app:useSimpleSummaryProvider="true" /> - + - \ No newline at end of file + \ No newline at end of file diff --git a/course/app/src/main/res/xml/preferences_about.xml b/course/app/src/main/res/xml/preferences_about.xml index 853af71..83ce453 100644 --- a/course/app/src/main/res/xml/preferences_about.xml +++ b/course/app/src/main/res/xml/preferences_about.xml @@ -2,31 +2,32 @@ - - + - - - - + - - - - - - + - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/course/build.gradle b/course/build.gradle index 14495ee..d8b9288 100644 --- a/course/build.gradle +++ b/course/build.gradle @@ -6,26 +6,31 @@ buildscript { // App dependencies coroutinesVersion = '1.4.2' gradleVersion = '4.2.2' - kotlinVersion = '1.5.20' + kotlinVersion = '1.5.31' roomVersion = '2.3.0' + latestAboutLibsRelease = '8.9.4' } repositories { google() - jcenter() + mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { classpath "com.android.tools.build:gradle:$gradleVersion" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.5" + classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:$latestAboutLibsRelease" } } allprojects { repositories { google() - jcenter() + mavenCentral() maven { url "https://jitpack.io" } } }