EditShareFragment.java 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. /**
  2. * ownCloud Android client application
  3. *
  4. * @author masensio
  5. * @author David A. Velasco
  6. * Copyright (C) 2015 ownCloud Inc.
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2,
  10. * as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. *
  20. */
  21. package com.owncloud.android.ui.fragment;
  22. import android.accounts.Account;
  23. import android.os.Bundle;
  24. import android.support.v4.app.Fragment;
  25. import android.view.LayoutInflater;
  26. import android.view.View;
  27. import android.view.ViewGroup;
  28. import android.widget.CheckBox;
  29. import android.widget.CompoundButton;
  30. import android.widget.Switch;
  31. import android.widget.TextView;
  32. import com.owncloud.android.R;
  33. import com.owncloud.android.datamodel.OCFile;
  34. import com.owncloud.android.lib.common.operations.RemoteOperationResult;
  35. import com.owncloud.android.lib.common.utils.Log_OC;
  36. import com.owncloud.android.lib.resources.shares.OCShare;
  37. import com.owncloud.android.lib.resources.shares.SharePermissionsBuilder;
  38. import com.owncloud.android.ui.activity.FileActivity;
  39. public class EditShareFragment extends Fragment {
  40. private static final String TAG = EditShareFragment.class.getSimpleName();
  41. /** The fragment initialization parameters */
  42. private static final String ARG_SHARE = "SHARE";
  43. private static final String ARG_FILE = "FILE";
  44. private static final String ARG_ACCOUNT = "ACCOUNT";
  45. /** Ids of CheckBoxes depending on R.id.canEdit CheckBox */
  46. private static final int sSubordinateCheckBoxIds[] = {
  47. R.id.canEditCreateCheckBox,
  48. R.id.canEditChangeCheckBox,
  49. R.id.canEditDeleteCheckBox
  50. };
  51. /** Share to show & edit, received as a parameter in construction time */
  52. private OCShare mShare;
  53. /** File bound to mShare, received as a parameter in construction time */
  54. private OCFile mFile;
  55. /** OC account holding the shared file, received as a parameter in construction time */
  56. private Account mAccount;
  57. /** Listener for changes on privilege checkboxes */
  58. private CompoundButton.OnCheckedChangeListener mOnPrivilegeChangeListener;
  59. /**
  60. * Public factory method to create new EditShareFragment instances.
  61. *
  62. * @param shareToEdit An {@link OCShare} to show and edit in the fragment
  63. * @param sharedFile The {@link OCFile} bound to 'shareToEdit'
  64. * @param account The ownCloud account holding 'sharedFile'
  65. * @return A new instance of fragment EditShareFragment.
  66. */
  67. public static EditShareFragment newInstance(OCShare shareToEdit, OCFile sharedFile, Account account) {
  68. EditShareFragment fragment = new EditShareFragment();
  69. Bundle args = new Bundle();
  70. args.putParcelable(ARG_SHARE, shareToEdit);
  71. args.putParcelable(ARG_FILE, sharedFile);
  72. args.putParcelable(ARG_ACCOUNT, account);
  73. fragment.setArguments(args);
  74. return fragment;
  75. }
  76. /**
  77. * Required empty public constructor
  78. */
  79. public EditShareFragment() {
  80. }
  81. /**
  82. * {@inheritDoc}
  83. */
  84. @Override
  85. public void onCreate(Bundle savedInstanceState) {
  86. super.onCreate(savedInstanceState);
  87. Log_OC.d(TAG, "onCreate");
  88. if (getArguments() != null) {
  89. mShare = getArguments().getParcelable(ARG_SHARE);
  90. mFile = getArguments().getParcelable(ARG_FILE);
  91. mAccount = getArguments().getParcelable(ARG_ACCOUNT);
  92. }
  93. }
  94. @Override
  95. public void onActivityCreated(Bundle savedInstanceState) {
  96. super.onActivityCreated(savedInstanceState);
  97. Log_OC.d(TAG, "onActivityCreated");
  98. getActivity().setTitle(mShare.getSharedWithDisplayName());
  99. }
  100. /**
  101. * {@inheritDoc}
  102. */
  103. @Override
  104. public View onCreateView(LayoutInflater inflater, ViewGroup container,
  105. Bundle savedInstanceState) {
  106. Log_OC.d(TAG, "onCreateView");
  107. // Inflate the layout for this fragment
  108. View view = inflater.inflate(R.layout.edit_share_layout, container, false);
  109. // Setup layout
  110. initPrivileges(view);
  111. initUnshareButton(view);
  112. initDoneButton(view);
  113. return view;
  114. }
  115. /**
  116. * Binds listener for user actions to enable or disable a privilege on the edited share
  117. * to the views receiving the user events.
  118. *
  119. * @param editShareView Root view in the fragment.
  120. */
  121. private void initPrivileges(View editShareView) {
  122. boolean setListener = false;
  123. if (mOnPrivilegeChangeListener == null) {
  124. mOnPrivilegeChangeListener = new OnPrivilegeChangeListener();
  125. setListener = true;
  126. }
  127. int sharePermissions = mShare.getPermissions();
  128. CompoundButton compound;
  129. compound = (CompoundButton) editShareView.findViewById(R.id.canShareSwitch);
  130. compound.setChecked((sharePermissions & OCShare.SHARE_PERMISSION_FLAG) > 0);
  131. if (setListener) {
  132. compound.setOnCheckedChangeListener(mOnPrivilegeChangeListener);
  133. }
  134. compound = (CompoundButton) editShareView.findViewById(R.id.canEditSwitch);
  135. int anyUpdatePermission =
  136. OCShare.CREATE_PERMISSION_FLAG |
  137. OCShare.UPDATE_PERMISSION_FLAG |
  138. OCShare.DELETE_PERMISSION_FLAG
  139. ;
  140. boolean canEdit = (sharePermissions & anyUpdatePermission) > 0;
  141. compound.setChecked(canEdit);
  142. if (setListener) {
  143. compound.setOnCheckedChangeListener(mOnPrivilegeChangeListener);
  144. }
  145. if (mFile.isFolder()) {
  146. compound = (CompoundButton) editShareView.findViewById(R.id.canEditCreateCheckBox);
  147. if (canEdit) {
  148. compound.setVisibility(View.VISIBLE);
  149. compound.setChecked((sharePermissions & OCShare.CREATE_PERMISSION_FLAG) > 0);
  150. }
  151. if (setListener) {
  152. compound.setOnCheckedChangeListener(mOnPrivilegeChangeListener);
  153. }
  154. compound = (CompoundButton) editShareView.findViewById(R.id.canEditChangeCheckBox);
  155. if (canEdit) {
  156. compound.setVisibility(View.VISIBLE);
  157. compound.setChecked((sharePermissions & OCShare.UPDATE_PERMISSION_FLAG) > 0);
  158. }
  159. if (setListener) {
  160. compound.setOnCheckedChangeListener(mOnPrivilegeChangeListener);
  161. }
  162. compound = (CompoundButton) editShareView.findViewById(R.id.canEditDeleteCheckBox);
  163. if (canEdit) {
  164. compound.setVisibility(View.VISIBLE);
  165. compound.setChecked((sharePermissions & OCShare.DELETE_PERMISSION_FLAG) > 0);
  166. }
  167. if (setListener) {
  168. compound.setOnCheckedChangeListener(mOnPrivilegeChangeListener);
  169. }
  170. } // else, trust in visibility GONE in R.layout.edit_share_layout
  171. }
  172. /**
  173. * Called when an operation to update share permissions finished.
  174. * s
  175. * @param result Result of the update operation
  176. */
  177. public void onUpdateSharePermissionsFinished(RemoteOperationResult result) {
  178. if (result.isSuccess()) {
  179. getFragmentManager().popBackStack();
  180. } else {
  181. if (getView() != null) {
  182. initPrivileges(getView());
  183. }
  184. }
  185. }
  186. /**
  187. * Listener for user actions that enable or disable a privilege
  188. */
  189. private class OnPrivilegeChangeListener
  190. implements CompoundButton.OnCheckedChangeListener {
  191. /**
  192. * Called by every {@link Switch} and {@link CheckBox} in the fragment to update
  193. * the state of its associated permission.
  194. *
  195. * @param compound {@link CompoundButton} toggled by the user
  196. * @param isChecked New switch state.
  197. */
  198. @Override
  199. public void onCheckedChanged(CompoundButton compound, boolean isChecked) {
  200. if (!isResumed()) {
  201. // very important, setCheched(...) is called automatically during
  202. // Fragment recreation on device rotations
  203. return;
  204. }
  205. /// else, getView() cannot be NULL
  206. CompoundButton subordinate;
  207. switch(compound.getId()) {
  208. case R.id.canShareSwitch:
  209. Log_OC.v(TAG, "canShareCheckBox toggled to " + isChecked);
  210. /// TODO?
  211. // option 1: direct update approach
  212. /*
  213. ((FileActivity) getActivity()).getFileOperationsHelper().
  214. setPrivilegeToShare(mFile, mShare, privilege, isChecked);
  215. */
  216. // option 2: nothing?
  217. break;
  218. case R.id.canEditSwitch:
  219. Log_OC.v(TAG, "canEditCheckBox toggled to " + isChecked);
  220. /// sync subordinate CheckBoxes
  221. if (mFile.isFolder()) {
  222. if (isChecked) {
  223. for (int i = 0; i < sSubordinateCheckBoxIds.length; i++) {
  224. //noinspection ConstantConditions, prevented in the method beginning
  225. subordinate = (CompoundButton) getView().findViewById(sSubordinateCheckBoxIds[i]);
  226. subordinate.setVisibility(View.VISIBLE);
  227. if (!subordinate.isChecked()) {
  228. toggleDisablingListener(subordinate);
  229. }
  230. }
  231. } else {
  232. for (int i = 0; i < sSubordinateCheckBoxIds.length; i++) {
  233. //noinspection ConstantConditions, prevented in the method beginning
  234. subordinate = (CompoundButton) getView().findViewById(sSubordinateCheckBoxIds[i]);
  235. subordinate.setVisibility(View.GONE);
  236. if (subordinate.isChecked()) {
  237. toggleDisablingListener(subordinate);
  238. }
  239. }
  240. }
  241. }
  242. /// TODO - anything else?; only if modification-on-change approach is taken
  243. break;
  244. case R.id.canEditCreateCheckBox:
  245. Log_OC.v(TAG, "canEditCreateCheckBox toggled to " + isChecked);
  246. syncCanEditSwitch(compound, isChecked);
  247. /// TODO - anything else?; only if modification-on-change approach is taken
  248. break;
  249. case R.id.canEditChangeCheckBox:
  250. Log_OC.v(TAG, "canEditChangeCheckBox toggled to " + isChecked);
  251. syncCanEditSwitch(compound, isChecked);
  252. /// TODO - anything else?; only if modification-on-change approach is taken
  253. break;
  254. case R.id.canEditDeleteCheckBox:
  255. Log_OC.v(TAG, "canEditDeleteCheckBox toggled to " + isChecked);
  256. syncCanEditSwitch(compound, isChecked);
  257. /// TODO - anything else?; only if modification-on-change approach is taken
  258. break;
  259. }
  260. // undo the toggle to grant the view will be correct if any intermediate dialog is cancelled or
  261. // the create/delete operation fails
  262. // ONLY if direct update approach is followed
  263. /*
  264. checkBoxView.setOnCheckedChangeListener(null);
  265. checkBoxView.toggle();
  266. checkBoxView.setOnCheckedChangeListener(mOnShareViaLinkSwitchCheckedChangeListener);
  267. */
  268. }
  269. /**
  270. * Sync value of "can edit" {@link Switch} according to a change in one of its subordinate checkboxes.
  271. *
  272. * If all the subordinates are disabled, "can edit" has to be disabled.
  273. *
  274. * If any subordinate is enabled, "can edit" has to be enabled.
  275. *
  276. * @param subordinateCheckBoxView Subordinate {@link CheckBox} that was changed.
  277. * @param isChecked 'true' iif subordinateCheckBoxView was checked.
  278. */
  279. private void syncCanEditSwitch(View subordinateCheckBoxView, boolean isChecked) {
  280. CompoundButton canEditCompound = (CompoundButton) getView().findViewById(R.id.canEditSwitch);
  281. if (isChecked) {
  282. if (!canEditCompound.isChecked()) {
  283. toggleDisablingListener(canEditCompound);
  284. }
  285. } else {
  286. boolean allDisabled = true;
  287. for (int i=0; allDisabled && i<sSubordinateCheckBoxIds.length; i++) {
  288. allDisabled &=
  289. sSubordinateCheckBoxIds[i] == subordinateCheckBoxView.getId() ||
  290. !((CheckBox) getView().findViewById(sSubordinateCheckBoxIds[i])).isChecked()
  291. ;
  292. }
  293. if (canEditCompound.isChecked() && allDisabled) {
  294. toggleDisablingListener(canEditCompound);
  295. for (int i=0; i<sSubordinateCheckBoxIds.length; i++) {
  296. getView().findViewById(sSubordinateCheckBoxIds[i]).setVisibility(View.GONE);
  297. }
  298. }
  299. }
  300. }
  301. /**
  302. * Toggle value of received {@link CompoundButton} granting that its change listener is not called.
  303. *
  304. * @param compound {@link CompoundButton} (switch or checkBox) to toggle without reporting to
  305. * the change listener
  306. */
  307. private void toggleDisablingListener(CompoundButton compound) {
  308. compound.setOnCheckedChangeListener(null);
  309. compound.toggle();
  310. compound.setOnCheckedChangeListener(mOnPrivilegeChangeListener);
  311. }
  312. }
  313. /**
  314. * Binds listener for user interactions on the 'unshare' button with the button itself.
  315. *
  316. * @param editShareView Root view in the fragment.
  317. */
  318. private void initUnshareButton(View editShareView) {
  319. TextView unshareButton = (TextView) editShareView.findViewById(R.id.unshareButton);
  320. unshareButton.setOnClickListener(new View.OnClickListener() {
  321. @Override
  322. public void onClick(View v) {
  323. ((FileActivity) getActivity()).getFileOperationsHelper().
  324. unshareFileWithUserOrGroup(
  325. mFile,
  326. mShare.getShareType(),
  327. mShare.getShareWith()
  328. )
  329. ;
  330. }
  331. });
  332. }
  333. /**
  334. * Binds listener for user interactions on the 'done' button with the button itself.
  335. *
  336. * @param editShareView Root view in the fragment.
  337. */
  338. private void initDoneButton(View editShareView) {
  339. TextView doneButton = (TextView) editShareView.findViewById(R.id.doneButton);
  340. doneButton.setOnClickListener(new View.OnClickListener() {
  341. @Override
  342. public void onClick(View v) {
  343. SharePermissionsBuilder spb = new SharePermissionsBuilder();
  344. spb.setSharePermission(getCanShareSwitch().isChecked());
  345. if (mFile.isFolder()) {
  346. spb.setUpdatePermission(getCanEditChangeCheckBox().isChecked())
  347. .setCreatePermission(getCanEditCreateCheckBox().isChecked())
  348. .setDeletePermission(getCanEditDeleteCheckBox().isChecked());
  349. } else {
  350. spb.setUpdatePermission(getCanEditSwitch().isChecked());
  351. }
  352. int permissions = spb.build();
  353. ((FileActivity) getActivity()).getFileOperationsHelper().
  354. setPermissionsToShare(
  355. mShare,
  356. permissions
  357. );
  358. }
  359. });
  360. }
  361. /**
  362. * Shortcut to access {@link Switch} R.id.canShareSwitch
  363. *
  364. * @return {@link Switch} R.id.canShareCheckBox or null if called before
  365. * {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)} finished.
  366. */
  367. private Switch getCanShareSwitch() {
  368. return (Switch) getView().findViewById(R.id.canShareSwitch);
  369. }
  370. /**
  371. * Shortcut to access {@link Switch} R.id.canEditSwitch
  372. *
  373. * @return {@link Switch} R.id.canEditSwitch or null if called before
  374. * {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)} finished.
  375. */
  376. private Switch getCanEditSwitch() {
  377. return (Switch) getView().findViewById(R.id.canEditSwitch);
  378. }
  379. /**
  380. * Shortcut to access {@link CheckBox} R.id.canEditCreateCheckBox
  381. *
  382. * @return {@link CheckBox} R.id.canEditCreateCheckBox or null if called before
  383. * {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)} finished.
  384. */
  385. private CheckBox getCanEditCreateCheckBox() {
  386. return (CheckBox) getView().findViewById(R.id.canEditCreateCheckBox);
  387. }
  388. /**
  389. * Shortcut to access {@link CheckBox} R.id.canEditChangeCheckBox
  390. *
  391. * @return {@link CheckBox} R.id.canEditChangeCheckBox or null if called before
  392. * {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)} finished.
  393. */
  394. private CheckBox getCanEditChangeCheckBox() {
  395. return (CheckBox) getView().findViewById(R.id.canEditChangeCheckBox);
  396. }
  397. /**
  398. * Shortcut to access {@link CheckBox} R.id.canEditDeleteCheckBox
  399. *
  400. * @return {@link CheckBox} R.id.canEditDeleteCheckBox or null if called before
  401. * {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)} finished.
  402. */
  403. private CheckBox getCanEditDeleteCheckBox() {
  404. return (CheckBox) getView().findViewById(R.id.canEditDeleteCheckBox);
  405. }
  406. }