Loading app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedFragment.kt +65 −40 Original line number Diff line number Diff line Loading @@ -4,60 +4,85 @@ * SPDX-FileCopyrightText: 2020-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: GPL-3.0-or-later */ package it.niedermann.owncloud.notes.branding; package it.niedermann.owncloud.notes.branding import android.os.Bundle; import android.util.TypedValue; import android.view.Menu; import android.view.MenuInflater; import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import com.nextcloud.android.common.ui.util.extensions.AppCompatActivityExtensionsKt; public abstract class BrandedFragment extends Fragment implements Branded { import android.os.Bundle import android.util.TypedValue import android.view.Menu import android.view.MenuInflater import androidx.annotation.ColorInt import androidx.appcompat.app.AppCompatActivity import androidx.core.view.forEach import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import com.nextcloud.android.common.ui.util.extensions.adjustUIForAPILevel35 import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch abstract class BrandedFragment : Fragment(), Branded { @JvmField @ColorInt protected int colorAccent; protected var colorAccent: Int = 0 @JvmField @ColorInt protected int colorPrimary; protected var colorPrimary: Int = 0 @Override public void onCreate(@Nullable Bundle savedInstanceState) { if (getActivity() instanceof AppCompatActivity appCompatActivity) { AppCompatActivityExtensionsKt.adjustUIForAPILevel35(appCompatActivity); override fun onCreate(savedInstanceState: Bundle?) { if (activity is AppCompatActivity) { val appCompatActivity = activity as AppCompatActivity appCompatActivity.adjustUIForAPILevel35() } super.onCreate(savedInstanceState); super.onCreate(savedInstanceState) } @Override public void onStart() { super.onStart(); override fun onStart() { super.onStart() final var context = requireContext(); final var typedValue = new TypedValue(); context.getTheme().resolveAttribute(com.google.android.material.R.attr.colorAccent, typedValue, true); colorAccent = typedValue.data; context.getTheme().resolveAttribute(com.google.android.material.R.attr.colorPrimary, typedValue, true); colorPrimary = typedValue.data; val context = requireContext() val typedValue = TypedValue() @ColorInt final int color = BrandingUtil.readBrandMainColor(context); applyBrand(color); context.theme.resolveAttribute( com.google.android.material.R.attr.colorAccent, typedValue, true ) colorAccent = typedValue.data context.theme.resolveAttribute( com.google.android.material.R.attr.colorPrimary, typedValue, true ) colorPrimary = typedValue.data @ColorInt val color = BrandingUtil.readBrandMainColor(context) applyBrand(color) } @Override public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); final var utils = BrandingUtil.of(colorAccent, requireContext()); @Suppress("DEPRECATION") @Deprecated("Deprecated in Java") override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { super.onCreateOptionsMenu(menu, inflater) val utils = BrandingUtil.of(colorAccent, requireContext()) for (int i = 0; i < menu.size(); i++) { if (menu.getItem(i).getIcon() != null) { utils.platform.colorToolbarMenuIcon(requireContext(), menu.getItem(i)); menu.forEach { menu -> menu.icon?.let { icon -> utils.platform.colorToolbarMenuIcon(requireContext(), menu) } } } fun lifecycleScopeIOJob(block: () -> Unit) { lifecycleScope.launch(Dispatchers.IO) { block() } } fun onMainThread(block: () -> Unit) { activity?.runOnUiThread { block() } } } app/src/main/java/it/niedermann/owncloud/notes/edit/NoteDirectEditFragment.kt +1 −1 Original line number Diff line number Diff line Loading @@ -193,7 +193,7 @@ class NoteDirectEditFragment : BaseNoteFragment(), Branded { Log.d(TAG, "loadNoteInWebView() called") context?.let { context -> val repository = DirectEditingRepository.getInstance(context) val repository = DirectEditingRepository.getInstance(context.applicationContext) val urlDisposable = repository.getDirectEditingUrl(account, note) .observeOn(AndroidSchedulers.mainThread()).subscribe({ url -> url?.let { Loading app/src/main/java/it/niedermann/owncloud/notes/edit/NoteEditFragment.java +25 −10 Original line number Diff line number Diff line Loading @@ -40,6 +40,8 @@ import it.niedermann.owncloud.notes.databinding.FragmentNoteEditBinding; import it.niedermann.owncloud.notes.persistence.entity.Note; import it.niedermann.owncloud.notes.shared.model.ISyncCallback; import it.niedermann.owncloud.notes.shared.util.DisplayUtils; import kotlin.Unit; import kotlin.jvm.functions.Function0; public class NoteEditFragment extends SearchableBaseNoteFragment { Loading Loading @@ -180,15 +182,24 @@ public class NoteEditFragment extends SearchableBaseNoteFragment { @Override protected void onNoteLoaded(Note note) { super.onNoteLoaded(note); if (binding == null) { return; } if (TextUtils.isEmpty(note.getContent())) { openSoftKeyboard(); } binding.editContent.setMarkdownString(note.getContent()); binding.editContent.setEnabled(true); lifecycleScopeIOJob(() -> { // load potential big note on IO Dispatchers final String content = note.getContent(); final var sp = PreferenceManager.getDefaultSharedPreferences(requireContext().getApplicationContext()); onMainThread(() -> { binding.editContent.setMarkdownString(content); binding.editContent.setEnabled(true); binding.editContent.setTextSize(TypedValue.COMPLEX_UNIT_PX, getFontSizeFromPreferences(requireContext(), sp)); if (sp.getBoolean(getString(R.string.pref_key_font), false)) { binding.editContent.setTypeface(Typeface.MONOSPACE); } Loading @@ -196,6 +207,10 @@ public class NoteEditFragment extends SearchableBaseNoteFragment { if (lastSelection > 0 && binding.editContent.length() >= lastSelection) { binding.editContent.setSelection(lastSelection); } return Unit.INSTANCE; }); return Unit.INSTANCE; }); } private void openSoftKeyboard() { Loading app/src/main/java/it/niedermann/owncloud/notes/edit/NotePreviewFragment.java +38 −13 Original line number Diff line number Diff line Loading @@ -34,12 +34,16 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException; import com.nextcloud.android.sso.exceptions.NoCurrentAccountSelectedException; import com.nextcloud.android.sso.helper.SingleAccountHelper; import com.owncloud.android.lib.common.utils.Log_OC; import it.niedermann.owncloud.notes.R; import it.niedermann.owncloud.notes.branding.BrandingUtil; import it.niedermann.owncloud.notes.databinding.FragmentNotePreviewBinding; import it.niedermann.owncloud.notes.persistence.entity.Note; import it.niedermann.owncloud.notes.shared.model.ISyncCallback; import it.niedermann.owncloud.notes.shared.util.SSOUtil; import kotlin.Unit; import kotlin.jvm.functions.Function0; public class NotePreviewFragment extends SearchableBaseNoteFragment implements OnRefreshListener { Loading Loading @@ -135,12 +139,27 @@ public class NotePreviewFragment extends SearchableBaseNoteFragment implements O super.onNoteLoaded(note); noteLoaded = true; registerInternalNoteLinkHandler(); changedText = note.getContent(); binding.singleNoteContent.setMarkdownString(note.getContent(), setScrollY); binding.singleNoteContent.getMarkdownString().observe(requireActivity(), (newContent) -> { lifecycleScopeIOJob(() -> { final String content = note.getContent(); changedText = content; onMainThread(() -> { binding.singleNoteContent.setMarkdownString(content, setScrollY); final var activity = getActivity(); if (activity == null) { return Unit.INSTANCE; } binding.singleNoteContent.getMarkdownString().observe(activity, (newContent) -> { changedText = newContent.toString(); saveNote(null); }); return Unit.INSTANCE; }); return Unit.INSTANCE; }); } protected void registerInternalNoteLinkHandler() { Loading Loading @@ -176,21 +195,27 @@ public class NotePreviewFragment extends SearchableBaseNoteFragment implements O public void onRefresh() { if (noteLoaded && repo.isSyncPossible() && SSOUtil.isConfigured(getContext())) { binding.swiperefreshlayout.setRefreshing(true); executor.submit(() -> { lifecycleScopeIOJob(() -> { try { final var account = repo.getAccountByName(SingleAccountHelper.getCurrentSingleSignOnAccount(requireContext()).name); repo.addCallbackPull(account, () -> executor.submit(() -> { repo.addCallbackPull(account, () -> { note = repo.getNoteById(note.getId()); changedText = note.getContent(); requireActivity().runOnUiThread(() -> { binding.singleNoteContent.setMarkdownString(note.getContent()); final String content = note.getContent(); changedText = content; onMainThread(() -> { binding.singleNoteContent.setMarkdownString(content); binding.swiperefreshlayout.setRefreshing(false); return Unit.INSTANCE; }); })); }); repo.scheduleSync(account, false); } catch (NextcloudFilesAppAccountNotFoundException | NoCurrentAccountSelectedException e) { e.printStackTrace(); } catch (Exception e) { Log_OC.e(TAG, "onRefresh exception: " + e); } return Unit.INSTANCE; }); } else { binding.swiperefreshlayout.setRefreshing(false); Loading Loading
app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedFragment.kt +65 −40 Original line number Diff line number Diff line Loading @@ -4,60 +4,85 @@ * SPDX-FileCopyrightText: 2020-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: GPL-3.0-or-later */ package it.niedermann.owncloud.notes.branding; package it.niedermann.owncloud.notes.branding import android.os.Bundle; import android.util.TypedValue; import android.view.Menu; import android.view.MenuInflater; import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import com.nextcloud.android.common.ui.util.extensions.AppCompatActivityExtensionsKt; public abstract class BrandedFragment extends Fragment implements Branded { import android.os.Bundle import android.util.TypedValue import android.view.Menu import android.view.MenuInflater import androidx.annotation.ColorInt import androidx.appcompat.app.AppCompatActivity import androidx.core.view.forEach import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import com.nextcloud.android.common.ui.util.extensions.adjustUIForAPILevel35 import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch abstract class BrandedFragment : Fragment(), Branded { @JvmField @ColorInt protected int colorAccent; protected var colorAccent: Int = 0 @JvmField @ColorInt protected int colorPrimary; protected var colorPrimary: Int = 0 @Override public void onCreate(@Nullable Bundle savedInstanceState) { if (getActivity() instanceof AppCompatActivity appCompatActivity) { AppCompatActivityExtensionsKt.adjustUIForAPILevel35(appCompatActivity); override fun onCreate(savedInstanceState: Bundle?) { if (activity is AppCompatActivity) { val appCompatActivity = activity as AppCompatActivity appCompatActivity.adjustUIForAPILevel35() } super.onCreate(savedInstanceState); super.onCreate(savedInstanceState) } @Override public void onStart() { super.onStart(); override fun onStart() { super.onStart() final var context = requireContext(); final var typedValue = new TypedValue(); context.getTheme().resolveAttribute(com.google.android.material.R.attr.colorAccent, typedValue, true); colorAccent = typedValue.data; context.getTheme().resolveAttribute(com.google.android.material.R.attr.colorPrimary, typedValue, true); colorPrimary = typedValue.data; val context = requireContext() val typedValue = TypedValue() @ColorInt final int color = BrandingUtil.readBrandMainColor(context); applyBrand(color); context.theme.resolveAttribute( com.google.android.material.R.attr.colorAccent, typedValue, true ) colorAccent = typedValue.data context.theme.resolveAttribute( com.google.android.material.R.attr.colorPrimary, typedValue, true ) colorPrimary = typedValue.data @ColorInt val color = BrandingUtil.readBrandMainColor(context) applyBrand(color) } @Override public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); final var utils = BrandingUtil.of(colorAccent, requireContext()); @Suppress("DEPRECATION") @Deprecated("Deprecated in Java") override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { super.onCreateOptionsMenu(menu, inflater) val utils = BrandingUtil.of(colorAccent, requireContext()) for (int i = 0; i < menu.size(); i++) { if (menu.getItem(i).getIcon() != null) { utils.platform.colorToolbarMenuIcon(requireContext(), menu.getItem(i)); menu.forEach { menu -> menu.icon?.let { icon -> utils.platform.colorToolbarMenuIcon(requireContext(), menu) } } } fun lifecycleScopeIOJob(block: () -> Unit) { lifecycleScope.launch(Dispatchers.IO) { block() } } fun onMainThread(block: () -> Unit) { activity?.runOnUiThread { block() } } }
app/src/main/java/it/niedermann/owncloud/notes/edit/NoteDirectEditFragment.kt +1 −1 Original line number Diff line number Diff line Loading @@ -193,7 +193,7 @@ class NoteDirectEditFragment : BaseNoteFragment(), Branded { Log.d(TAG, "loadNoteInWebView() called") context?.let { context -> val repository = DirectEditingRepository.getInstance(context) val repository = DirectEditingRepository.getInstance(context.applicationContext) val urlDisposable = repository.getDirectEditingUrl(account, note) .observeOn(AndroidSchedulers.mainThread()).subscribe({ url -> url?.let { Loading
app/src/main/java/it/niedermann/owncloud/notes/edit/NoteEditFragment.java +25 −10 Original line number Diff line number Diff line Loading @@ -40,6 +40,8 @@ import it.niedermann.owncloud.notes.databinding.FragmentNoteEditBinding; import it.niedermann.owncloud.notes.persistence.entity.Note; import it.niedermann.owncloud.notes.shared.model.ISyncCallback; import it.niedermann.owncloud.notes.shared.util.DisplayUtils; import kotlin.Unit; import kotlin.jvm.functions.Function0; public class NoteEditFragment extends SearchableBaseNoteFragment { Loading Loading @@ -180,15 +182,24 @@ public class NoteEditFragment extends SearchableBaseNoteFragment { @Override protected void onNoteLoaded(Note note) { super.onNoteLoaded(note); if (binding == null) { return; } if (TextUtils.isEmpty(note.getContent())) { openSoftKeyboard(); } binding.editContent.setMarkdownString(note.getContent()); binding.editContent.setEnabled(true); lifecycleScopeIOJob(() -> { // load potential big note on IO Dispatchers final String content = note.getContent(); final var sp = PreferenceManager.getDefaultSharedPreferences(requireContext().getApplicationContext()); onMainThread(() -> { binding.editContent.setMarkdownString(content); binding.editContent.setEnabled(true); binding.editContent.setTextSize(TypedValue.COMPLEX_UNIT_PX, getFontSizeFromPreferences(requireContext(), sp)); if (sp.getBoolean(getString(R.string.pref_key_font), false)) { binding.editContent.setTypeface(Typeface.MONOSPACE); } Loading @@ -196,6 +207,10 @@ public class NoteEditFragment extends SearchableBaseNoteFragment { if (lastSelection > 0 && binding.editContent.length() >= lastSelection) { binding.editContent.setSelection(lastSelection); } return Unit.INSTANCE; }); return Unit.INSTANCE; }); } private void openSoftKeyboard() { Loading
app/src/main/java/it/niedermann/owncloud/notes/edit/NotePreviewFragment.java +38 −13 Original line number Diff line number Diff line Loading @@ -34,12 +34,16 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException; import com.nextcloud.android.sso.exceptions.NoCurrentAccountSelectedException; import com.nextcloud.android.sso.helper.SingleAccountHelper; import com.owncloud.android.lib.common.utils.Log_OC; import it.niedermann.owncloud.notes.R; import it.niedermann.owncloud.notes.branding.BrandingUtil; import it.niedermann.owncloud.notes.databinding.FragmentNotePreviewBinding; import it.niedermann.owncloud.notes.persistence.entity.Note; import it.niedermann.owncloud.notes.shared.model.ISyncCallback; import it.niedermann.owncloud.notes.shared.util.SSOUtil; import kotlin.Unit; import kotlin.jvm.functions.Function0; public class NotePreviewFragment extends SearchableBaseNoteFragment implements OnRefreshListener { Loading Loading @@ -135,12 +139,27 @@ public class NotePreviewFragment extends SearchableBaseNoteFragment implements O super.onNoteLoaded(note); noteLoaded = true; registerInternalNoteLinkHandler(); changedText = note.getContent(); binding.singleNoteContent.setMarkdownString(note.getContent(), setScrollY); binding.singleNoteContent.getMarkdownString().observe(requireActivity(), (newContent) -> { lifecycleScopeIOJob(() -> { final String content = note.getContent(); changedText = content; onMainThread(() -> { binding.singleNoteContent.setMarkdownString(content, setScrollY); final var activity = getActivity(); if (activity == null) { return Unit.INSTANCE; } binding.singleNoteContent.getMarkdownString().observe(activity, (newContent) -> { changedText = newContent.toString(); saveNote(null); }); return Unit.INSTANCE; }); return Unit.INSTANCE; }); } protected void registerInternalNoteLinkHandler() { Loading Loading @@ -176,21 +195,27 @@ public class NotePreviewFragment extends SearchableBaseNoteFragment implements O public void onRefresh() { if (noteLoaded && repo.isSyncPossible() && SSOUtil.isConfigured(getContext())) { binding.swiperefreshlayout.setRefreshing(true); executor.submit(() -> { lifecycleScopeIOJob(() -> { try { final var account = repo.getAccountByName(SingleAccountHelper.getCurrentSingleSignOnAccount(requireContext()).name); repo.addCallbackPull(account, () -> executor.submit(() -> { repo.addCallbackPull(account, () -> { note = repo.getNoteById(note.getId()); changedText = note.getContent(); requireActivity().runOnUiThread(() -> { binding.singleNoteContent.setMarkdownString(note.getContent()); final String content = note.getContent(); changedText = content; onMainThread(() -> { binding.singleNoteContent.setMarkdownString(content); binding.swiperefreshlayout.setRefreshing(false); return Unit.INSTANCE; }); })); }); repo.scheduleSync(account, false); } catch (NextcloudFilesAppAccountNotFoundException | NoCurrentAccountSelectedException e) { e.printStackTrace(); } catch (Exception e) { Log_OC.e(TAG, "onRefresh exception: " + e); } return Unit.INSTANCE; }); } else { binding.swiperefreshlayout.setRefreshing(false); Loading