package com.nutomic.syncthingandroid.views; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.databinding.DataBindingUtil; import android.net.Uri; import android.support.annotation.NonNull; import android.support.v4.content.ContextCompat; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.TextView; import android.widget.Toast; import com.nutomic.syncthingandroid.BuildConfig; import com.nutomic.syncthingandroid.R; import com.nutomic.syncthingandroid.databinding.ItemFolderListBinding; import com.nutomic.syncthingandroid.model.Folder; import com.nutomic.syncthingandroid.model.Model; import com.nutomic.syncthingandroid.service.RestApi; import com.nutomic.syncthingandroid.util.Util; import java.io.File; import java.util.HashMap; import static android.view.View.GONE; import static android.view.View.VISIBLE; /** * Generates item views for folder items. */ public class FoldersAdapter extends ArrayAdapter<Folder> { private final HashMap<String, Model> mModels = new HashMap<>(); public FoldersAdapter(Context context) { super(context, 0); } @Override @NonNull public View getView(int position, View convertView, @NonNull ViewGroup parent) { ItemFolderListBinding binding = (convertView == null) ? DataBindingUtil.inflate(LayoutInflater.from(getContext()), R.layout.item_folder_list, parent, false) : DataBindingUtil.bind(convertView); Folder folder = getItem(position); Model model = mModels.get(folder.id); binding.label.setText(TextUtils.isEmpty(folder.label) ? folder.id : folder.label); binding.state.setTextColor(ContextCompat.getColor(getContext(), R.color.text_green)); binding.directory.setText(folder.path); binding.openFolder.setOnClickListener(v -> { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(new File(folder.path)), "resource/folder"); try { getContext().startActivity(intent); } catch (ActivityNotFoundException e) { Toast.makeText(getContext(), R.string.toast_no_file_manager, Toast.LENGTH_SHORT).show(); } }); if (model != null) { int percentage = (model.localBytes != 0) ? Math.round(100 * model.inSyncBytes / model.localBytes) : 100; binding.state.setText(getLocalizedState(getContext(), model.state, percentage)); binding.items.setVisibility(VISIBLE); binding.items.setText(getContext() .getString(R.string.files, model.inSyncFiles, model.localFiles)); binding.size.setVisibility(VISIBLE); binding.size.setText(getContext().getString(R.string.folder_size_format, Util.readableFileSize(getContext(), model.inSyncBytes), Util.readableFileSize(getContext(), model.localBytes))); setTextOrHide(binding.invalid, model.invalid); } else { binding.items.setVisibility(GONE); binding.size.setVisibility(GONE); setTextOrHide(binding.invalid, folder.invalid); } return binding.getRoot(); } /** * Returns the folder's state as a localized string. */ public static String getLocalizedState(Context c, String state, int percentage) { switch (state) { case "idle": return c.getString(R.string.state_idle); case "scanning": return c.getString(R.string.state_scanning); case "cleaning": return c.getString(R.string.state_cleaning); case "syncing": return c.getString(R.string.state_syncing, percentage); case "error": return c.getString(R.string.state_error); case "unknown": // Fallthrough case "": return c.getString(R.string.state_unknown); } if (BuildConfig.DEBUG) { throw new AssertionError("Unexpected folder state " + state); } return ""; } /** * Requests updated model info from the api for all visible items. */ public void updateModel(RestApi api) { for (int i = 0; i < getCount(); i++) { api.getModel(getItem(i).id, this::onReceiveModel); } } public void onReceiveModel(String folderId, Model model) { mModels.put(folderId, model); notifyDataSetChanged(); } private void setTextOrHide(TextView view, String text) { if (TextUtils.isEmpty(text)) { view.setVisibility(GONE); } else { view.setText(text); view.setVisibility(VISIBLE); } } }