ShareFileFragment.java 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856
  1. /**
  2. * ownCloud Android client application
  3. *
  4. * @author masensio
  5. * @author David A. Velasco
  6. * @author Juan Carlos González Cabrero
  7. * Copyright (C) 2015 ownCloud Inc.
  8. * <p/>
  9. * This program is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License version 2,
  11. * as published by the Free Software Foundation.
  12. * <p/>
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. * <p/>
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. package com.owncloud.android.ui.fragment;
  22. import android.accounts.Account;
  23. import android.app.Activity;
  24. import android.graphics.Bitmap;
  25. import android.os.Bundle;
  26. import android.support.v4.app.Fragment;
  27. import android.support.v7.widget.AppCompatButton;
  28. import android.view.LayoutInflater;
  29. import android.view.View;
  30. import android.view.ViewGroup;
  31. import android.widget.Button;
  32. import android.widget.CompoundButton;
  33. import android.widget.ImageView;
  34. import android.widget.ListAdapter;
  35. import android.widget.ListView;
  36. import android.widget.ScrollView;
  37. import android.widget.Switch;
  38. import android.widget.TextView;
  39. import android.widget.Toast;
  40. import com.owncloud.android.R;
  41. import com.owncloud.android.authentication.AccountUtils;
  42. import com.owncloud.android.datamodel.OCFile;
  43. import com.owncloud.android.datamodel.ThumbnailsCacheManager;
  44. import com.owncloud.android.lib.common.utils.Log_OC;
  45. import com.owncloud.android.lib.resources.shares.OCShare;
  46. import com.owncloud.android.lib.resources.shares.ShareType;
  47. import com.owncloud.android.lib.resources.status.OCCapability;
  48. import com.owncloud.android.ui.activity.FileActivity;
  49. import com.owncloud.android.ui.adapter.ShareUserListAdapter;
  50. import com.owncloud.android.ui.dialog.ExpirationDatePickerDialogFragment;
  51. import com.owncloud.android.utils.DisplayUtils;
  52. import com.owncloud.android.utils.MimetypeIconUtil;
  53. import java.text.SimpleDateFormat;
  54. import java.util.ArrayList;
  55. import java.util.Date;
  56. /**
  57. * Fragment for Sharing a file with sharees (users or groups) or creating
  58. * a public link.
  59. * <p/>
  60. * A simple {@link Fragment} subclass.
  61. * <p/>
  62. * Activities that contain this fragment must implement the
  63. * {@link ShareFragmentListener} interface
  64. * to handle interaction events.
  65. * <p/>
  66. * Use the {@link ShareFileFragment#newInstance} factory method to
  67. * create an instance of this fragment.
  68. */
  69. public class ShareFileFragment extends Fragment
  70. implements ShareUserListAdapter.ShareUserAdapterListener {
  71. private static final String TAG = ShareFileFragment.class.getSimpleName();
  72. /**
  73. * The fragment initialization parameters
  74. */
  75. private static final String ARG_FILE = "FILE";
  76. private static final String ARG_ACCOUNT = "ACCOUNT";
  77. // /** Tag for dialog */
  78. // private static final String FTAG_CHOOSER_DIALOG = "CHOOSER_DIALOG";
  79. /**
  80. * File to share, received as a parameter in construction time
  81. */
  82. private OCFile mFile;
  83. /**
  84. * OC account holding the file to share, received as a parameter in construction time
  85. */
  86. private Account mAccount;
  87. /**
  88. * Reference to parent listener
  89. */
  90. private ShareFragmentListener mListener;
  91. /**
  92. * List of private shares bound to the file
  93. */
  94. private ArrayList<OCShare> mPrivateShares;
  95. /**
  96. * Capabilities of the server
  97. */
  98. private OCCapability mCapabilities;
  99. /**
  100. * Adapter to show private shares
  101. */
  102. private ShareUserListAdapter mUserGroupsAdapter = null;
  103. /**
  104. * Public share bound to the file
  105. */
  106. private OCShare mPublicShare;
  107. /**
  108. * Listener for changes on switch to share / unshare publicly
  109. */
  110. private CompoundButton.OnCheckedChangeListener mOnShareViaLinkSwitchCheckedChangeListener;
  111. /**
  112. * Listener for user actions to set, update or clear password on public link
  113. */
  114. private OnPasswordInteractionListener mOnPasswordInteractionListener = null;
  115. /**
  116. * Listener for user actions to set, update or clear expiration date on public link
  117. */
  118. private OnExpirationDateInteractionListener mOnExpirationDateInteractionListener = null;
  119. /**
  120. * Listener for user actions to set or unset edit permission on public link
  121. */
  122. private OnEditPermissionInteractionListener mOnEditPermissionInteractionListener = null;
  123. /**
  124. * Public factory method to create new ShareFileFragment instances.
  125. *
  126. * @param fileToShare An {@link OCFile} to show in the fragment
  127. * @param account An ownCloud account
  128. * @return A new instance of fragment ShareFileFragment.
  129. */
  130. public static ShareFileFragment newInstance(OCFile fileToShare, Account account) {
  131. ShareFileFragment fragment = new ShareFileFragment();
  132. Bundle args = new Bundle();
  133. args.putParcelable(ARG_FILE, fileToShare);
  134. args.putParcelable(ARG_ACCOUNT, account);
  135. fragment.setArguments(args);
  136. return fragment;
  137. }
  138. /**
  139. * Required empty public constructor
  140. */
  141. public ShareFileFragment() {
  142. }
  143. /**
  144. * {@inheritDoc}
  145. */
  146. @Override
  147. public void onCreate(Bundle savedInstanceState) {
  148. super.onCreate(savedInstanceState);
  149. Log_OC.d(TAG, "onCreate");
  150. if (getArguments() != null) {
  151. mFile = getArguments().getParcelable(ARG_FILE);
  152. mAccount = getArguments().getParcelable(ARG_ACCOUNT);
  153. }
  154. }
  155. /**
  156. * {@inheritDoc}
  157. */
  158. @Override
  159. public View onCreateView(LayoutInflater inflater, ViewGroup container,
  160. Bundle savedInstanceState) {
  161. Log_OC.d(TAG, "onCreateView");
  162. // Inflate the layout for this fragment
  163. View view = inflater.inflate(R.layout.share_file_layout, container, false);
  164. // Setup layout
  165. // Image
  166. ImageView icon = (ImageView) view.findViewById(R.id.shareFileIcon);
  167. icon.setImageResource(MimetypeIconUtil.getFileTypeIconId(mFile.getMimetype(),
  168. mFile.getFileName()));
  169. if (mFile.isImage()) {
  170. String remoteId = String.valueOf(mFile.getRemoteId());
  171. Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(remoteId);
  172. if (thumbnail != null) {
  173. icon.setImageBitmap(thumbnail);
  174. }
  175. }
  176. // Name
  177. TextView filename = (TextView) view.findViewById(R.id.shareFileName);
  178. filename.setText(mFile.getFileName());
  179. // Size
  180. TextView size = (TextView) view.findViewById(R.id.shareFileSize);
  181. if (mFile.isFolder()) {
  182. size.setVisibility(View.GONE);
  183. } else {
  184. size.setText(DisplayUtils.bytesToHumanReadable(mFile.getFileLength()));
  185. }
  186. // Add User Button
  187. Button addUserGroupButton = (Button)
  188. view.findViewById(R.id.addUserButton);
  189. addUserGroupButton.setOnClickListener(new View.OnClickListener() {
  190. @Override
  191. public void onClick(View view) {
  192. boolean shareWithUsersEnable = AccountUtils.hasSearchUsersSupport(mAccount);
  193. if (shareWithUsersEnable) {
  194. // Show Search Fragment
  195. mListener.showSearchUsersAndGroups();
  196. } else {
  197. String message = getString(R.string.share_sharee_unavailable);
  198. Toast.makeText(getActivity(), message, Toast.LENGTH_LONG).show();
  199. }
  200. }
  201. });
  202. // Set listener for user actions on switch for sharing/unsharing via link
  203. initShareViaLinkListener(view);
  204. // Set listener for user actions on expiration date
  205. initExpirationListener(view);
  206. // Set listener for user actions on password
  207. initPasswordListener(view);
  208. // Set listener for user actions on edit permission
  209. initEditPermissionListener(view);
  210. return view;
  211. }
  212. /**
  213. * Binds listener for user actions to create or delete a public share
  214. * to the views receiving the user events.
  215. *
  216. * @param shareView Root view in the fragment.
  217. */
  218. private void initShareViaLinkListener(View shareView) {
  219. mOnShareViaLinkSwitchCheckedChangeListener = new OnShareViaLinkListener();
  220. Switch shareViaLinkSwitch = (Switch) shareView.findViewById(R.id.shareViaLinkSectionSwitch);
  221. shareViaLinkSwitch.setOnCheckedChangeListener(mOnShareViaLinkSwitchCheckedChangeListener);
  222. }
  223. /**
  224. * Listener for user actions that create or delete a public share.
  225. */
  226. private class OnShareViaLinkListener
  227. implements CompoundButton.OnCheckedChangeListener {
  228. /**
  229. * Called by R.id.shareViaLinkSectionSwitch to create or delete a public link.
  230. *
  231. * @param switchView {@link Switch} toggled by the user, R.id.shareViaLinkSectionSwitch
  232. * @param isChecked New switch state.
  233. */
  234. @Override
  235. public void onCheckedChanged(CompoundButton switchView, boolean isChecked) {
  236. if (!isResumed()) {
  237. // very important, setCheched(...) is called automatically during
  238. // Fragment recreation on device rotations
  239. return;
  240. }
  241. if (isChecked) {
  242. if (mCapabilities != null &&
  243. mCapabilities.getFilesSharingPublicPasswordEnforced().isTrue()) {
  244. // password enforced by server, request to the user before trying to create
  245. ((FileActivity) getActivity()).getFileOperationsHelper().
  246. requestPasswordForShareViaLink(mFile, true);
  247. } else {
  248. // create without password if not enforced by server or we don't know if enforced;
  249. ((FileActivity) getActivity()).getFileOperationsHelper().
  250. shareFileViaLink(mFile, null);
  251. // FileActivtiy#onCreateShareViaLinkOperationFinish still handles the guess of enforcement
  252. // for server in versions previous to OwnCloudVersion#MINIMUM_VERSION_CAPABILITIES_API
  253. }
  254. } else {
  255. ((FileActivity) getActivity()).getFileOperationsHelper().
  256. unshareFileViaLink(mFile);
  257. }
  258. // undo the toggle to grant the view will be correct if any intermediate dialog is cancelled or
  259. // the create/delete operation fails
  260. switchView.setOnCheckedChangeListener(null);
  261. switchView.toggle();
  262. switchView.setOnCheckedChangeListener(mOnShareViaLinkSwitchCheckedChangeListener);
  263. }
  264. }
  265. /**
  266. * Binds listener for user actions that start any update on a expiration date
  267. * for the public link to the views receiving the user events.
  268. *
  269. * @param shareView Root view in the fragment.
  270. */
  271. private void initExpirationListener(View shareView) {
  272. mOnExpirationDateInteractionListener = new OnExpirationDateInteractionListener();
  273. ((Switch) shareView.findViewById(R.id.shareViaLinkExpirationSwitch)).
  274. setOnCheckedChangeListener(mOnExpirationDateInteractionListener);
  275. shareView.findViewById(R.id.shareViaLinkExpirationLabel).
  276. setOnClickListener(mOnExpirationDateInteractionListener);
  277. shareView.findViewById(R.id.shareViaLinkExpirationValue).
  278. setOnClickListener(mOnExpirationDateInteractionListener);
  279. }
  280. /**
  281. * Listener for user actions that start any update on the expiration date for the public link.
  282. */
  283. private class OnExpirationDateInteractionListener
  284. implements CompoundButton.OnCheckedChangeListener, View.OnClickListener {
  285. /**
  286. * Called by R.id.shareViaLinkExpirationSwitch to set or clear the expiration date.
  287. *
  288. * @param switchView {@link Switch} toggled by the user, R.id.shareViaLinkExpirationSwitch
  289. * @param isChecked New switch state.
  290. */
  291. @Override
  292. public void onCheckedChanged(CompoundButton switchView, boolean isChecked) {
  293. if (!isResumed()) {
  294. // very important, setCheched(...) is called automatically during
  295. // Fragment recreation on device rotations
  296. return;
  297. }
  298. if (isChecked) {
  299. ExpirationDatePickerDialogFragment dialog =
  300. ExpirationDatePickerDialogFragment.newInstance(mFile, -1);
  301. dialog.show(
  302. getActivity().getSupportFragmentManager(),
  303. ExpirationDatePickerDialogFragment.DATE_PICKER_DIALOG
  304. );
  305. } else {
  306. ((FileActivity) getActivity()).getFileOperationsHelper().
  307. setExpirationDateToShareViaLink(mFile, -1);
  308. }
  309. // undo the toggle to grant the view will be correct if the dialog is cancelled
  310. switchView.setOnCheckedChangeListener(null);
  311. switchView.toggle();
  312. switchView.setOnCheckedChangeListener(mOnExpirationDateInteractionListener);
  313. }
  314. /**
  315. * Called by R.id.shareViaLinkExpirationLabel or R.id.shareViaLinkExpirationValue
  316. * to change the current expiration date.
  317. *
  318. * @param expirationView Label or value view touched by the user.
  319. */
  320. @Override
  321. public void onClick(View expirationView) {
  322. if (mPublicShare != null && mPublicShare.getExpirationDate() > 0) {
  323. long chosenDateInMillis = -1;
  324. if (mPublicShare != null) {
  325. chosenDateInMillis = mPublicShare.getExpirationDate();
  326. }
  327. ExpirationDatePickerDialogFragment dialog =
  328. ExpirationDatePickerDialogFragment.newInstance(
  329. mFile,
  330. chosenDateInMillis
  331. );
  332. dialog.show(
  333. getActivity().getSupportFragmentManager(),
  334. ExpirationDatePickerDialogFragment.DATE_PICKER_DIALOG
  335. );
  336. }
  337. }
  338. }
  339. /**
  340. * Binds listener for user actions that start any update on a password for the public link
  341. * to the views receiving the user events.
  342. *
  343. * @param shareView Root view in the fragment.
  344. */
  345. private void initPasswordListener(View shareView) {
  346. mOnPasswordInteractionListener = new OnPasswordInteractionListener();
  347. ((Switch) shareView.findViewById(R.id.shareViaLinkPasswordSwitch)).
  348. setOnCheckedChangeListener(mOnPasswordInteractionListener);
  349. shareView.findViewById(R.id.shareViaLinkPasswordLabel).
  350. setOnClickListener(mOnPasswordInteractionListener);
  351. shareView.findViewById(R.id.shareViaLinkPasswordValue).
  352. setOnClickListener(mOnPasswordInteractionListener);
  353. }
  354. /**
  355. * Listener for user actions that start any update on a password for the public link.
  356. */
  357. private class OnPasswordInteractionListener
  358. implements CompoundButton.OnCheckedChangeListener, View.OnClickListener {
  359. /**
  360. * Called by R.id.shareViaLinkPasswordSwitch to set or clear the password.
  361. *
  362. * @param switchView {@link Switch} toggled by the user, R.id.shareViaLinkPasswordSwitch
  363. * @param isChecked New switch state.
  364. */
  365. @Override
  366. public void onCheckedChanged(CompoundButton switchView, boolean isChecked) {
  367. if (!isResumed()) {
  368. // very important, setCheched(...) is called automatically during
  369. // Fragment recreation on device rotations
  370. return;
  371. }
  372. if (isChecked) {
  373. ((FileActivity) getActivity()).getFileOperationsHelper().
  374. requestPasswordForShareViaLink(mFile, false);
  375. } else {
  376. ((FileActivity) getActivity()).getFileOperationsHelper().
  377. setPasswordToShareViaLink(mFile, ""); // "" clears
  378. }
  379. // undo the toggle to grant the view will be correct if the dialog is cancelled
  380. switchView.setOnCheckedChangeListener(null);
  381. switchView.toggle();
  382. switchView.setOnCheckedChangeListener(mOnPasswordInteractionListener);
  383. }
  384. /**
  385. * Called by R.id.shareViaLinkPasswordLabel or R.id.shareViaLinkPasswordValue
  386. * to change the current password.
  387. *
  388. * @param passwordView Label or value view touched by the user.
  389. */
  390. @Override
  391. public void onClick(View passwordView) {
  392. if (mPublicShare != null && mPublicShare.isPasswordProtected()) {
  393. ((FileActivity) getActivity()).getFileOperationsHelper().
  394. requestPasswordForShareViaLink(mFile, false);
  395. }
  396. }
  397. }
  398. /**
  399. * Binds listener for user actions that start any update the edit permissions
  400. * for the public link to the views receiving the user events.
  401. *
  402. * @param shareView Root view in the fragment.
  403. */
  404. private void initEditPermissionListener(View shareView) {
  405. mOnEditPermissionInteractionListener = new OnEditPermissionInteractionListener();
  406. ((Switch) shareView.findViewById(R.id.shareViaLinkEditPermissionSwitch)).
  407. setOnCheckedChangeListener(mOnEditPermissionInteractionListener);
  408. }
  409. /**
  410. * Listener for user actions that start any update on the edit permissions for the public link.
  411. */
  412. private class OnEditPermissionInteractionListener
  413. implements CompoundButton.OnCheckedChangeListener {
  414. /**
  415. * Called by R.id.shareViaLinkEditPermissionSwitch to set or clear the edit permission.
  416. *
  417. * @param switchView {@link Switch} toggled by the user, R.id.shareViaLinkEditPermissionSwitch
  418. * @param isChecked New switch state.
  419. */
  420. @Override
  421. public void onCheckedChanged(CompoundButton switchView, boolean isChecked) {
  422. if (!isResumed()) {
  423. // very important, setCheched(...) is called automatically during
  424. // Fragment recreation on device rotations
  425. return;
  426. }
  427. boolean permission;
  428. if (isChecked) {
  429. permission = true;
  430. } else {
  431. permission = false;
  432. }
  433. ((FileActivity) getActivity()).getFileOperationsHelper().
  434. setUploadPermissionsToShare(
  435. mFile,
  436. permission
  437. );
  438. ;
  439. // undo the toggle to grant the view will be correct if the dialog is cancelled
  440. switchView.setOnCheckedChangeListener(null);
  441. switchView.toggle();
  442. switchView.setOnCheckedChangeListener(mOnEditPermissionInteractionListener);
  443. }
  444. }
  445. @Override
  446. public void onActivityCreated(Bundle savedInstanceState) {
  447. super.onActivityCreated(savedInstanceState);
  448. Log_OC.d(TAG, "onActivityCreated");
  449. getActivity().setTitle(R.string.share_dialog_title);
  450. // Load known capabilities of the server from DB
  451. refreshCapabilitiesFromDB();
  452. // Load data into the list of private shares
  453. refreshUsersOrGroupsListFromDB();
  454. // Load data of public share, if exists
  455. refreshPublicShareFromDB();
  456. }
  457. @Override
  458. public void onAttach(Activity activity) {
  459. super.onAttach(activity);
  460. try {
  461. mListener = (ShareFragmentListener) activity;
  462. } catch (ClassCastException e) {
  463. throw new ClassCastException(activity.toString()
  464. + " must implement OnShareFragmentInteractionListener");
  465. }
  466. }
  467. @Override
  468. public void onDetach() {
  469. super.onDetach();
  470. mListener = null;
  471. }
  472. /**
  473. * Get known server capabilities from DB
  474. * <p/>
  475. * Depends on the parent Activity provides a {@link com.owncloud.android.datamodel.FileDataStorageManager}
  476. * instance ready to use. If not ready, does nothing.
  477. */
  478. public void refreshCapabilitiesFromDB() {
  479. if (((FileActivity) mListener).getStorageManager() != null) {
  480. mCapabilities = ((FileActivity) mListener).getStorageManager().
  481. getCapability(mAccount.name);
  482. }
  483. }
  484. /**
  485. * Get users and groups from the DB to fill in the "share with" list.
  486. * <p/>
  487. * Depends on the parent Activity provides a {@link com.owncloud.android.datamodel.FileDataStorageManager}
  488. * instance ready to use. If not ready, does nothing.
  489. */
  490. public void refreshUsersOrGroupsListFromDB() {
  491. if (((FileActivity) mListener).getStorageManager() != null) {
  492. // Get Users and Groups
  493. mPrivateShares = ((FileActivity) mListener).getStorageManager().getSharesWithForAFile(
  494. mFile.getRemotePath(),
  495. mAccount.name
  496. );
  497. // Update list of users/groups
  498. updateListOfUserGroups();
  499. }
  500. }
  501. private void updateListOfUserGroups() {
  502. // Update list of users/groups
  503. // TODO Refactoring: create a new {@link ShareUserListAdapter} instance with every call should not be needed
  504. mUserGroupsAdapter = new ShareUserListAdapter(
  505. getActivity(),
  506. R.layout.share_user_item,
  507. mPrivateShares,
  508. this
  509. );
  510. // Show data
  511. TextView noShares = (TextView) getView().findViewById(R.id.shareNoUsers);
  512. ListView usersList = (ListView) getView().findViewById(R.id.shareUsersList);
  513. if (mPrivateShares.size() > 0) {
  514. noShares.setVisibility(View.GONE);
  515. usersList.setVisibility(View.VISIBLE);
  516. usersList.setAdapter(mUserGroupsAdapter);
  517. setListViewHeightBasedOnChildren(usersList);
  518. } else {
  519. noShares.setVisibility(View.VISIBLE);
  520. usersList.setVisibility(View.GONE);
  521. }
  522. // Set Scroll to initial position
  523. ScrollView scrollView = (ScrollView) getView().findViewById(R.id.shareScroll);
  524. scrollView.scrollTo(0, 0);
  525. }
  526. @Override
  527. public void unshareButtonPressed(OCShare share) {
  528. // Unshare
  529. Log_OC.d(TAG, "Unsharing " + share.getSharedWithDisplayName());
  530. mListener.unshareWith(share);
  531. }
  532. @Override
  533. public void editShare(OCShare share) {
  534. // move to fragment to edit share
  535. Log_OC.d(TAG, "Editing " + share.getSharedWithDisplayName());
  536. mListener.showEditShare(share);
  537. }
  538. /**
  539. * Get public link from the DB to fill in the "Share link" section in the UI.
  540. * <p/>
  541. * Takes into account server capabilities before reading database.
  542. * <p/>
  543. * Depends on the parent Activity provides a {@link com.owncloud.android.datamodel.FileDataStorageManager}
  544. * instance ready to use. If not ready, does nothing.
  545. */
  546. public void refreshPublicShareFromDB() {
  547. if (isPublicShareDisabled()) {
  548. hidePublicShare();
  549. } else if (((FileActivity) mListener).getStorageManager() != null) {
  550. // Get public share
  551. mPublicShare = ((FileActivity) mListener).getStorageManager().getFirstShareByPathAndType(
  552. mFile.getRemotePath(),
  553. ShareType.PUBLIC_LINK,
  554. ""
  555. );
  556. // Update public share section
  557. updatePublicShareSection();
  558. }
  559. }
  560. /**
  561. * @return 'True' when public share is disabled in the server
  562. */
  563. private boolean isPublicShareDisabled() {
  564. return (mCapabilities != null &&
  565. mCapabilities.getFilesSharingPublicEnabled().isFalse()
  566. );
  567. }
  568. /**
  569. * Updates in the UI the section about public share with the information in the current
  570. * public share bound to mFile, if any
  571. */
  572. private void updatePublicShareSection() {
  573. if (mPublicShare != null && ShareType.PUBLIC_LINK.equals(mPublicShare.getShareType())) {
  574. /// public share bound -> expand section
  575. Switch shareViaLinkSwitch = getShareViaLinkSwitch();
  576. if (!shareViaLinkSwitch.isChecked()) {
  577. // set null listener before setChecked() to prevent infinite loop of calls
  578. shareViaLinkSwitch.setOnCheckedChangeListener(null);
  579. shareViaLinkSwitch.setChecked(true);
  580. shareViaLinkSwitch.setOnCheckedChangeListener(
  581. mOnShareViaLinkSwitchCheckedChangeListener
  582. );
  583. }
  584. getExpirationDateSection().setVisibility(View.VISIBLE);
  585. getPasswordSection().setVisibility(View.VISIBLE);
  586. if (mFile.isFolder() && !mCapabilities.getFilesSharingPublicUpload().isFalse()) {
  587. getEditPermissionSection().setVisibility(View.VISIBLE);
  588. } else {
  589. getEditPermissionSection().setVisibility(View.GONE);
  590. }
  591. // GetLink button
  592. AppCompatButton getLinkButton = getGetLinkButton();
  593. getLinkButton.setVisibility(View.VISIBLE);
  594. getLinkButton.setOnClickListener(new View.OnClickListener() {
  595. @Override
  596. public void onClick(View v) {
  597. //GetLink from the server and show ShareLinkToDialog
  598. ((FileActivity) getActivity()).getFileOperationsHelper().
  599. getFileWithLink(mFile);
  600. }
  601. });
  602. /// update state of expiration date switch and message depending on expiration date
  603. Switch expirationDateSwitch = getExpirationDateSwitch();
  604. // set null listener before setChecked() to prevent infinite loop of calls
  605. expirationDateSwitch.setOnCheckedChangeListener(null);
  606. long expirationDate = mPublicShare.getExpirationDate();
  607. if (expirationDate > 0) {
  608. if (!expirationDateSwitch.isChecked()) {
  609. expirationDateSwitch.toggle();
  610. }
  611. String formattedDate =
  612. SimpleDateFormat.getDateInstance().format(
  613. new Date(expirationDate)
  614. );
  615. getExpirationDateValue().setText(formattedDate);
  616. } else {
  617. if (expirationDateSwitch.isChecked()) {
  618. expirationDateSwitch.toggle();
  619. }
  620. getExpirationDateValue().setText(R.string.empty);
  621. }
  622. // recover listener
  623. expirationDateSwitch.setOnCheckedChangeListener(
  624. mOnExpirationDateInteractionListener
  625. );
  626. /// update state of password switch and message depending on password protection
  627. Switch passwordSwitch = getPasswordSwitch();
  628. // set null listener before setChecked() to prevent infinite loop of calls
  629. passwordSwitch.setOnCheckedChangeListener(null);
  630. if (mPublicShare.isPasswordProtected()) {
  631. if (!passwordSwitch.isChecked()) {
  632. passwordSwitch.toggle();
  633. }
  634. getPasswordValue().setVisibility(View.VISIBLE);
  635. } else {
  636. if (passwordSwitch.isChecked()) {
  637. passwordSwitch.toggle();
  638. }
  639. getPasswordValue().setVisibility(View.INVISIBLE);
  640. }
  641. // recover listener
  642. passwordSwitch.setOnCheckedChangeListener(
  643. mOnPasswordInteractionListener
  644. );
  645. /// update state of the edit permission switch
  646. Switch editPermissionSwitch = getEditPermissionSwitch();
  647. if(getEditPermissionSection().getVisibility() == View.VISIBLE) {
  648. // set null listener before setChecked() to prevent infinite loop of calls
  649. editPermissionSwitch.setOnCheckedChangeListener(null);
  650. if (mPublicShare.getPermissions() > OCShare.READ_PERMISSION_FLAG) {
  651. if (!editPermissionSwitch.isChecked()) {
  652. editPermissionSwitch.toggle();
  653. }
  654. } else {
  655. if (editPermissionSwitch.isChecked()) {
  656. editPermissionSwitch.toggle();
  657. }
  658. }
  659. // recover listener
  660. editPermissionSwitch.setOnCheckedChangeListener(
  661. mOnEditPermissionInteractionListener
  662. );
  663. }
  664. } else {
  665. /// no public share -> collapse section
  666. Switch shareViaLinkSwitch = getShareViaLinkSwitch();
  667. if (shareViaLinkSwitch.isChecked()) {
  668. shareViaLinkSwitch.setOnCheckedChangeListener(null);
  669. getShareViaLinkSwitch().setChecked(false);
  670. shareViaLinkSwitch.setOnCheckedChangeListener(
  671. mOnShareViaLinkSwitchCheckedChangeListener
  672. );
  673. }
  674. getExpirationDateSection().setVisibility(View.GONE);
  675. getPasswordSection().setVisibility(View.GONE);
  676. getEditPermissionSection().setVisibility(View.GONE);
  677. getGetLinkButton().setVisibility(View.GONE);
  678. }
  679. }
  680. /// BEWARE: next methods will failed with NullPointerException if called before onCreateView() finishes
  681. private Switch getShareViaLinkSwitch() {
  682. return (Switch) getView().findViewById(R.id.shareViaLinkSectionSwitch);
  683. }
  684. private View getExpirationDateSection() {
  685. return getView().findViewById(R.id.shareViaLinkExpirationSection);
  686. }
  687. private Switch getExpirationDateSwitch() {
  688. return (Switch) getView().findViewById(R.id.shareViaLinkExpirationSwitch);
  689. }
  690. private TextView getExpirationDateValue() {
  691. return (TextView) getView().findViewById(R.id.shareViaLinkExpirationValue);
  692. }
  693. private View getPasswordSection() {
  694. return getView().findViewById(R.id.shareViaLinkPasswordSection);
  695. }
  696. private Switch getPasswordSwitch() {
  697. return (Switch) getView().findViewById(R.id.shareViaLinkPasswordSwitch);
  698. }
  699. private TextView getPasswordValue() {
  700. return (TextView) getView().findViewById(R.id.shareViaLinkPasswordValue);
  701. }
  702. private View getEditPermissionSection() {
  703. return getView().findViewById(R.id.shareViaLinkEditPermissionSection);
  704. }
  705. private Switch getEditPermissionSwitch() {
  706. return (Switch) getView().findViewById(R.id.shareViaLinkEditPermissionSwitch);
  707. }
  708. private AppCompatButton getGetLinkButton() {
  709. return (AppCompatButton) getView().findViewById(R.id.shareViaLinkGetLinkButton);
  710. }
  711. /**
  712. * Hides all the UI elements related to public share
  713. */
  714. private void hidePublicShare() {
  715. getShareViaLinkSwitch().setVisibility(View.GONE);
  716. getExpirationDateSection().setVisibility(View.GONE);
  717. getPasswordSection().setVisibility(View.GONE);
  718. getEditPermissionSection().setVisibility(View.GONE);
  719. getGetLinkButton().setVisibility(View.GONE);
  720. }
  721. public static void setListViewHeightBasedOnChildren(ListView listView) {
  722. ListAdapter listAdapter = listView.getAdapter();
  723. if (listAdapter == null) {
  724. return;
  725. }
  726. int desiredWidth = View.MeasureSpec.makeMeasureSpec(listView.getWidth(), View.MeasureSpec.AT_MOST);
  727. int totalHeight = 0;
  728. View view = null;
  729. for (int i = 0; i < listAdapter.getCount(); i++) {
  730. view = listAdapter.getView(i, view, listView);
  731. if (i == 0) {
  732. view.setLayoutParams(new ViewGroup.LayoutParams(desiredWidth, ViewGroup.LayoutParams.WRAP_CONTENT));
  733. }
  734. view.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);
  735. totalHeight += view.getMeasuredHeight();
  736. }
  737. ViewGroup.LayoutParams params = listView.getLayoutParams();
  738. params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
  739. listView.setLayoutParams(params);
  740. listView.requestLayout();
  741. }
  742. }