ShareFileFragment.java 33 KB

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