fix: show empty state hints for bottom sheet fragments (closes #1157, closes #1158)

This commit is contained in:
Akash Yadav
2023-07-31 22:46:02 +05:30
parent bd0bfe827f
commit 94bbd0a4f4
18 changed files with 398 additions and 268 deletions
@@ -29,7 +29,7 @@ import com.itsaky.androidide.fragments.AppLogFragment;
import com.itsaky.androidide.fragments.DiagnosticsListFragment;
import com.itsaky.androidide.fragments.IDELogFragment;
import com.itsaky.androidide.fragments.SearchResultFragment;
import com.itsaky.androidide.fragments.SimpleOutputFragment;
import com.itsaky.androidide.fragments.BuildOutputFragment;
import com.itsaky.androidide.utils.ILogger;
import java.util.ArrayList;
@@ -48,7 +48,7 @@ public class EditorBottomSheetTabAdapter extends FragmentStateAdapter {
this.fragments.add(
new Tab(
fragmentActivity.getString(R.string.build_output),
SimpleOutputFragment.class,
BuildOutputFragment.class,
++index));
this.fragments.add(
new Tab(fragmentActivity.getString(R.string.app_logs), AppLogFragment.class, ++index));
@@ -117,8 +117,8 @@ public class EditorBottomSheetTabAdapter extends FragmentStateAdapter {
}
@Nullable
public SimpleOutputFragment getBuildOutputFragment() {
return findFragmentByClass(SimpleOutputFragment.class);
public BuildOutputFragment getBuildOutputFragment() {
return findFragmentByClass(BuildOutputFragment.class);
}
@Nullable
@@ -19,11 +19,13 @@ package com.itsaky.androidide.fragments
import android.os.Bundle
import android.view.View
import com.blankj.utilcode.util.ThreadUtils
import com.itsaky.androidide.R
class SimpleOutputFragment : NonEditableEditorFragment() {
class BuildOutputFragment : NonEditableEditorFragment() {
private val unsavedLines: MutableList<String?> = ArrayList()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
emptyStateViewModel.emptyMessage.value = getString(R.string.msg_emptyview_buildoutput)
if (unsavedLines.isNotEmpty()) {
for (line in unsavedLines) {
editor?.append("${line!!.trim()}\n")
@@ -48,7 +50,9 @@ class SimpleOutputFragment : NonEditableEditorFragment() {
} else {
"${output}\n"
}
editor!!.append(message)
editor!!.append(message).also {
emptyStateViewModel.isEmpty.value = false
}
}
}
}
@@ -1,95 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE 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.
*
* AndroidIDE 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.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.fragments;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.itsaky.androidide.adapters.DiagnosticsAdapter;
import com.itsaky.androidide.ui.EmptyView;
import java.util.ArrayList;
public class DiagnosticsListFragment extends Fragment {
private RecyclerView list;
private EmptyView emptyView;
private DiagnosticsAdapter unsavedAdapter;
@Nullable
@Override
public View onCreateView(
@NonNull LayoutInflater inflater,
@Nullable ViewGroup parent,
@Nullable Bundle savedInstanceState) {
final var container = new LinearLayout(inflater.getContext());
container.setOrientation(LinearLayout.VERTICAL);
container.setLayoutParams(new ViewGroup.LayoutParams(-1, -1));
this.list = new RecyclerView(inflater.getContext());
this.emptyView = new EmptyView(inflater.getContext());
container.addView(list, new LinearLayout.LayoutParams(-1, -1));
container.addView(emptyView, new LinearLayout.LayoutParams(-1, -1));
return container;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
list.setLayoutManager(new LinearLayoutManager(list.getContext()));
list.setAdapter(
unsavedAdapter != null ? unsavedAdapter : new DiagnosticsAdapter(new ArrayList<>(), null));
unsavedAdapter = null;
}
@Override
public void onDestroyView() {
super.onDestroyView();
unsavedAdapter = null;
list = null;
emptyView = null;
}
public void setAdapter(@NonNull DiagnosticsAdapter adapter) {
if (list != null) {
list.setAdapter(adapter);
} else {
unsavedAdapter = adapter;
}
}
public void handleResultVisibility(boolean error) {
if (emptyView != null && list != null) {
emptyView.setVisibility(error ? View.VISIBLE : View.GONE);
list.setVisibility(error ? View.GONE : View.VISIBLE);
}
}
}
@@ -0,0 +1,35 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE 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.
*
* AndroidIDE 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.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.fragments
import android.os.Bundle
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import com.itsaky.androidide.R
import com.itsaky.androidide.adapters.DiagnosticsAdapter
class DiagnosticsListFragment : RecyclerViewFragment<DiagnosticsAdapter>() {
override fun onCreateAdapter(): RecyclerView.Adapter<*> {
return DiagnosticsAdapter(ArrayList(), null)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
emptyStateViewModel.emptyMessage.value = getString(R.string.msg_emptyview_diagnostics)
}
}
@@ -0,0 +1,79 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE 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.
*
* AndroidIDE 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.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.fragments
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.viewModels
import androidx.viewbinding.ViewBinding
import com.itsaky.androidide.databinding.FragmentEmptyStateBinding
import com.itsaky.androidide.viewmodel.EmptyStateFragmentViewModel
/**
* A fragment that shows a message when there is no data to show in the subclass fragment.
*
* @author Akash Yadav
*/
abstract class EmptyStateFragment<T : ViewBinding>(layout: Int,
bind: (View) -> T) : FragmentWithBinding<T>(layout, bind) {
protected var emptyStateBinding: FragmentEmptyStateBinding? = null
private set
protected val emptyStateViewModel by viewModels<EmptyStateFragmentViewModel>()
internal var isEmpty: Boolean
get() = emptyStateViewModel.isEmpty.value ?: false
set(value) {
emptyStateViewModel.isEmpty.value = value
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
return FragmentEmptyStateBinding.inflate(inflater, container, false).also { emptyStateBinding ->
this.emptyStateBinding = emptyStateBinding
// add the main fragment view
emptyStateBinding.root.addView(
super.onCreateView(inflater, emptyStateBinding.root, savedInstanceState)
)
}.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
emptyStateViewModel.isEmpty.observe(viewLifecycleOwner) { isEmpty ->
emptyStateBinding?.apply {
root.displayedChild = if (isEmpty) 0 else 1
}
}
emptyStateViewModel.emptyMessage.observe(viewLifecycleOwner) { message ->
emptyStateBinding?.emptyView?.message = message
}
}
override fun onDestroyView() {
this.emptyStateBinding = null
super.onDestroyView()
}
}
@@ -17,6 +17,9 @@
package com.itsaky.androidide.fragments
import android.os.Bundle
import android.view.View
import com.itsaky.androidide.R
import com.itsaky.androidide.utils.ILogger
/**
@@ -43,6 +46,11 @@ class IDELogFragment : LogViewFragment() {
override fun isSimpleFormattingEnabled() = true
override fun getFilename() = "ide_logs"
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
emptyStateViewModel.emptyMessage.value = getString(R.string.msg_emptyview_idelogs)
}
override fun onDestroy() {
super.onDestroy()
ILogger.removeLogListener(logListener)
@@ -57,4 +65,9 @@ class IDELogFragment : LogViewFragment() {
class AppLogFragment : LogViewFragment() {
override fun isSimpleFormattingEnabled() = false
override fun getFilename() = "app_logs"
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
emptyStateViewModel.emptyMessage.value = getString(R.string.msg_emptyview_applogs)
}
}
@@ -20,11 +20,9 @@ package com.itsaky.androidide.fragments
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.blankj.utilcode.util.ThreadUtils
import com.itsaky.androidide.R
import com.itsaky.androidide.databinding.FragmentLogBinding
import com.itsaky.androidide.editor.language.log.LogLanguage
import com.itsaky.androidide.editor.schemes.IDEColorSchemeProvider
@@ -44,7 +42,9 @@ import kotlin.math.min
*
* @author Akash Yadav
*/
abstract class LogViewFragment : Fragment(), ShareableOutputFragment {
abstract class LogViewFragment :
EmptyStateFragment<FragmentLogBinding>(R.layout.fragment_log, FragmentLogBinding::bind),
ShareableOutputFragment {
companion object {
@@ -78,8 +78,6 @@ abstract class LogViewFragment : Fragment(), ShareableOutputFragment {
const val MAX_LINE_COUNT = TRIM_ON_LINE_COUNT - 300
}
var binding: FragmentLogBinding? = null
private var lastLog = -1L
private val cacheLock = ReentrantLock()
@@ -161,7 +159,13 @@ abstract class LogViewFragment : Fragment(), ShareableOutputFragment {
}
private fun append(chars: CharSequence?) {
chars?.let { ThreadUtils.runOnUiThread { binding?.editor?.append(chars) } }
chars?.let {
ThreadUtils.runOnUiThread {
_binding?.editor?.append(chars)?.also {
emptyStateViewModel.isEmpty.value = false
}
}
}
}
private fun trimLinesAtStart() {
@@ -171,7 +175,7 @@ abstract class LogViewFragment : Fragment(), ShareableOutputFragment {
}
ThreadUtils.runOnUiThread {
binding?.editor?.text?.apply {
_binding?.editor?.text?.apply {
if (lineCount <= TRIM_ON_LINE_COUNT) {
isTrimming.set(false)
return@apply
@@ -193,18 +197,9 @@ abstract class LogViewFragment : Fragment(), ShareableOutputFragment {
appendLog(line)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
binding = FragmentLogBinding.inflate(inflater, container, false)
return binding!!.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val editor = this.binding!!.editor
val editor = this.binding.editor
editor.props.autoIndent = false
editor.isEditable = false
editor.dividerWidth = 0f
@@ -246,24 +241,17 @@ abstract class LogViewFragment : Fragment(), ShareableOutputFragment {
}
override fun onDestroyView() {
binding?.editor?.release()
_binding?.editor?.release()
super.onDestroyView()
}
override fun onDestroy() {
super.onDestroy()
this.binding = null
}
override fun getContent(): String {
if (this.binding == null) {
return ""
}
return this.binding!!.editor.text.toString()
return this._binding?.editor?.text?.toString() ?: ""
}
override fun clearOutput() {
binding?.editor?.setText("")
_binding?.editor?.setText("")?.also {
emptyStateViewModel.isEmpty.value = true
}
}
}
@@ -18,40 +18,29 @@
package com.itsaky.androidide.fragments;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.itsaky.androidide.R;
import com.itsaky.androidide.databinding.FragmentNonEditableEditorBinding;
import com.itsaky.androidide.editor.ui.IDEEditor;
import com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE;
import com.itsaky.androidide.utils.TypefaceUtilsKt;
import com.itsaky.androidide.editor.ui.IDEEditor;
import io.github.rosemoe.sora.lang.EmptyLanguage;
public abstract class NonEditableEditorFragment extends Fragment
public abstract class NonEditableEditorFragment extends
EmptyStateFragment<FragmentNonEditableEditorBinding>
implements ShareableOutputFragment {
private FragmentNonEditableEditorBinding binding;
@Nullable
@Override
public View onCreateView(
@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
this.binding = FragmentNonEditableEditorBinding.inflate(inflater, container, false);
return binding.getRoot();
public NonEditableEditorFragment() {
super(R.layout.fragment_non_editable_editor, FragmentNonEditableEditorBinding::bind);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
final var editor = binding.getRoot();
getEmptyStateViewModel().getEmptyMessage().setValue(createEmptyStateMessage());
final var editor = getBinding().getRoot();
editor.setEditable(false);
editor.setDividerWidth(0);
editor.setEditorLanguage(new EmptyLanguage());
@@ -63,10 +52,8 @@ public abstract class NonEditableEditorFragment extends Fragment
editor.setColorScheme(SchemeAndroidIDE.newInstance(requireContext()));
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
private CharSequence createEmptyStateMessage() {
return null;
}
@NonNull
@@ -82,6 +69,7 @@ public abstract class NonEditableEditorFragment extends Fragment
@Nullable
public IDEEditor getEditor() {
final var binding = get_binding();
if (binding == null) {
return null;
}
@@ -103,5 +91,6 @@ public abstract class NonEditableEditorFragment extends Fragment
// Editing CodeEditor's content is a synchronized operation
editor.getText().delete(0, editor.getText().length());
getEmptyStateViewModel().isEmpty().setValue(true);
}
}
@@ -0,0 +1,81 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE 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.
*
* AndroidIDE 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.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.fragments
import android.os.Bundle
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.LayoutManager
import com.itsaky.androidide.R
import com.itsaky.androidide.databinding.FragmentRecyclerviewBinding
/**
* A fragment which shows a [RecyclerView].
*
* @author Akash Yadav
*/
abstract class RecyclerViewFragment<A : RecyclerView.Adapter<*>> :
EmptyStateFragment<FragmentRecyclerviewBinding>(R.layout.fragment_recyclerview,
FragmentRecyclerviewBinding::bind) {
private var unsavedAdapter: A? = null
/**
* Creates the adapter for the [RecyclerView].
*/
protected abstract fun onCreateAdapter(): RecyclerView.Adapter<*>
/**
* Creates the layout manager for the [RecyclerView].
*/
protected open fun onCreateLayoutManager(): LayoutManager {
return LinearLayoutManager(requireContext())
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.root.apply {
layoutManager = onCreateLayoutManager()
adapter = unsavedAdapter ?: onCreateAdapter()
}
unsavedAdapter = null
checkIsEmpty()
}
override fun onDestroyView() {
super.onDestroyView()
unsavedAdapter = null
}
/**
* Set the adapter for the [RecyclerView].
*/
fun setAdapter(adapter: A) {
_binding?.root?.let { list -> list.adapter = adapter } ?: run { unsavedAdapter = adapter }
checkIsEmpty()
}
private fun checkIsEmpty() {
if (_binding?.root?.adapter?.itemCount == 0) {
emptyStateViewModel.isEmpty.value = true
}
}
}
@@ -1,103 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE 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.
*
* AndroidIDE 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.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.fragments;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.itsaky.androidide.adapters.SearchListAdapter;
import com.itsaky.androidide.ui.EmptyView;
import java.util.Collections;
import kotlin.Unit;
public class SearchResultFragment extends Fragment {
private RecyclerView list;
private EmptyView emptyView;
private SearchListAdapter unsavedAdapter;
@Nullable
@Override
public View onCreateView(
@NonNull LayoutInflater inflater,
@Nullable ViewGroup parent,
@Nullable Bundle savedInstanceState) {
final var container = new LinearLayout(inflater.getContext());
container.setOrientation(LinearLayout.VERTICAL);
container.setLayoutParams(new ViewGroup.LayoutParams(-1, -1));
this.list = new RecyclerView(inflater.getContext());
this.emptyView = new EmptyView(inflater.getContext());
container.addView(list, new LinearLayout.LayoutParams(-1, -1));
container.addView(emptyView, new LinearLayout.LayoutParams(-1, -1));
return container;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
list.setLayoutManager(new LinearLayoutManager(list.getContext()));
list.setAdapter(
unsavedAdapter != null
? unsavedAdapter
: new SearchListAdapter(Collections.emptyMap(), this::noOp, this::noOp));
unsavedAdapter = null;
}
@Override
public void onDestroyView() {
super.onDestroyView();
unsavedAdapter = null;
list = null;
emptyView = null;
}
public void setAdapter(@NonNull final SearchListAdapter adapter) {
if (list == null) {
unsavedAdapter = adapter;
return;
}
this.list.setAdapter(adapter);
}
public void handleResultVisibility(boolean error) {
if (emptyView != null && list != null) {
emptyView.setVisibility(error ? View.VISIBLE : View.GONE);
list.setVisibility(error ? View.GONE : View.VISIBLE);
}
}
private Unit noOp(Object obj) {
return Unit.INSTANCE;
}
}
@@ -0,0 +1,28 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE 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.
*
* AndroidIDE 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.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.fragments
import androidx.recyclerview.widget.RecyclerView
import com.itsaky.androidide.adapters.SearchListAdapter
class SearchResultFragment : RecyclerViewFragment<SearchListAdapter>() {
override fun onCreateAdapter(): RecyclerView.Adapter<*> {
val noOp: (Any) -> Unit = {}
return SearchListAdapter(emptyMap(), noOp, noOp)
}
}
@@ -86,13 +86,15 @@ constructor(
localContext.resources.getDimension(R.dimen.editor_sheet_collapsed_height)
}
@JvmField var binding: LayoutEditorBottomSheetBinding
@JvmField
var binding: LayoutEditorBottomSheetBinding
val pagerAdapter: EditorBottomSheetTabAdapter
private val log = ILogger.newInstance("EditorBottomSheet")
companion object {
const val CHILD_SYMBOL_INPUT = 0
const val CHILD_HEADER = 1
const val CHILD_ACTION = 2
@@ -138,7 +140,8 @@ constructor(
val filename = fragment.getFilename()
@Suppress("DEPRECATION")
val progress = android.app.ProgressDialog.show(context, null, context.getString(string.please_wait))
val progress = android.app.ProgressDialog.show(context, null,
context.getString(string.please_wait))
executeAsync(fragment::getContent) {
progress.dismiss()
shareText(it, filename)
@@ -234,11 +237,11 @@ constructor(
}
fun handleDiagnosticsResultVisibility(errorVisible: Boolean) {
runOnUiThread { pagerAdapter.diagnosticsFragment?.handleResultVisibility(errorVisible) }
runOnUiThread { pagerAdapter.diagnosticsFragment?.isEmpty = errorVisible }
}
fun handleSearchResultVisibility(errorVisible: Boolean) {
runOnUiThread { pagerAdapter.searchResultFragment?.handleResultVisibility(errorVisible) }
runOnUiThread { pagerAdapter.searchResultFragment?.isEmpty = errorVisible }
}
fun setDiagnosticsAdapter(adapter: DiagnosticsAdapter) {
@@ -300,7 +303,8 @@ constructor(
flashError(context.getString(string.msg_output_text_extraction_failed))
return
}
val pd = android.app.ProgressDialog.show(context, null, context.getString(string.please_wait), true, false)
val pd = android.app.ProgressDialog.show(context, null, context.getString(string.please_wait),
true, false)
executeAsyncProvideError(
Callable { writeTempFile(text, type) },
CallbackWithError<File> { result: File?, error: Throwable? ->
@@ -21,16 +21,22 @@
package com.itsaky.androidide.ui;
import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import com.itsaky.androidide.R;
import com.itsaky.androidide.utils.ResourceUtilsKt;
public class EmptyView extends RelativeLayout {
private static final int MESSAGE_TEXTVIEW = View.generateViewId();
private CharSequence message = null;
public EmptyView(Context context) {
this(context, null);
}
@@ -54,7 +60,8 @@ public class EmptyView extends RelativeLayout {
removeAllViews();
TextView text = new TextView(getContext());
text.setText(com.itsaky.androidide.resources.R.string.msg_empty_view);
text.setId(MESSAGE_TEXTVIEW);
text.setText(getMessage());
text.setTextColor(ResourceUtilsKt.resolveAttr(getContext(), R.attr.colorSecondaryVariant));
text.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
@@ -63,4 +70,18 @@ public class EmptyView extends RelativeLayout {
addView(text, params);
}
public void setMessage(CharSequence message) {
this.message = message;
final TextView text = findViewById(MESSAGE_TEXTVIEW);
if (text != null) {
text.setText(getMessage());
}
}
@NonNull
public CharSequence getMessage() {
return TextUtils.isEmpty(message) ? getContext().getString(R.string.msg_empty_view) : message;
}
}
@@ -0,0 +1,31 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE 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.
*
* AndroidIDE 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.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.viewmodel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.itsaky.androidide.R
/**
* @author Akash Yadav
*/
class EmptyStateFragmentViewModel : ViewModel() {
val isEmpty = MutableLiveData(true)
val emptyMessage = MutableLiveData<CharSequence>("")
}
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ This file is part of AndroidIDE.
~
~ AndroidIDE 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.
~
~ AndroidIDE 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.
~
~ You should have received a copy of the GNU General Public License
~ along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
-->
<ViewFlipper xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.itsaky.androidide.ui.EmptyView
android:id="@+id/empty_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</ViewFlipper>
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ This file is part of AndroidIDE.
~
~ AndroidIDE 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.
~
~ AndroidIDE 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.
~
~ You should have received a copy of the GNU General Public License
~ along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
-->
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" />
@@ -30,7 +30,7 @@ import androidx.viewbinding.ViewBinding
* @author Akash Yadav
*/
abstract class FragmentWithBinding<T : ViewBinding>(@LayoutRes layout: Int,
private val bind: (View) -> T
private val bind: (View) -> T
) : BaseFragment(layout) {
@Suppress("PropertyName")
@@ -41,10 +41,14 @@ abstract class FragmentWithBinding<T : ViewBinding>(@LayoutRes layout: Int,
_binding) { "Cannot access ViewBinding. Fragment may have been destroyed." }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
savedInstanceState: Bundle?
): View {
return super.onCreateView(inflater, container, savedInstanceState)!!
.also { _binding = bind(it) }
.also(this::doBind)
}
protected fun doBind(it: View) {
_binding = bind(it)
}
override fun onDestroyView() {
+5 -1
View File
@@ -23,7 +23,7 @@
<string name="ide_preferences">IDE preferences</string>
<string name="discussions_on_telegram">Discussions on Telegram</string>
<string name="official_tg_channel">Official Telegram Channel</string>
<string name="msg_empty_view">I have nothing to show you…</string>
<string name="msg_empty_view">No data</string>
<string name="title_terminal">Terminal</string>
<string name="reset">Reset</string>
<string name="app_logs">App Logs</string>
@@ -586,4 +586,8 @@
<string name="idepref_group_debugging">Debugging</string>
<string name="idepref_devOptions_dumpLogs_title">Dump logs</string>
<string name="idepref_devOptions_dumpLogs_summary">Dump AndroidIDE logs to $HOME/.androidide/logs</string>
<string name="msg_emptyview_applogs">Run the debug variant of your application to view its logs here.</string>
<string name="msg_emptyview_idelogs">Logs from the IDE are shown here.</string>
<string name="msg_emptyview_diagnostics">Open a file to show its diagnostic results</string>
<string name="msg_emptyview_buildoutput">"Build the application or run a task to see its build output here. "</string>
</resources>