Fix #3013 Swipe chat based deletion

Signed-off-by: Julien Eluard <julien.eluard@gmail.com>
This commit is contained in:
Hanwen Cheng 2018-03-02 00:26:59 +08:00 committed by Julien Eluard
parent 3a33e04410
commit 502a28ec7a
No known key found for this signature in database
GPG Key ID: 6FD7DB5437FCBEF6
10 changed files with 145 additions and 48 deletions

View File

@ -16,4 +16,8 @@
(defn save
[{:keys [browser-id] :as browser}]
(data-store/save browser (exists? browser-id)))
(data-store/save browser (exists? browser-id)))
(defn delete
[browser-id]
(data-store/delete browser-id))

View File

@ -14,6 +14,11 @@
[browser update?]
(realm/save @realm/account-realm :browser browser update?))
(defn delete
[browser-id]
(when-let [browser (realm/get-one-by-field @realm/account-realm :browser :browser-id browser-id)]
(realm/delete @realm/account-realm browser)))
(defn exists?
[browser-id]
(realm/exists? @realm/account-realm :browser {:browser-id browser-id}))

View File

@ -35,9 +35,6 @@
(defn stop-animation [anim-value]
(.stopAnimation anim-value))
(defn value [anim-value]
(.-value anim-value))
(defn set-value [anim-value value]
(.setValue anim-value value))

View File

@ -23,6 +23,11 @@
(fn [browser]
(browser-store/save browser)))
(re-frame/reg-fx
:remove-browser
(fn [browser-id]
(browser-store/delete browser-id)))
(defn match-url [url]
(str (when (and url (not (re-find #"^[a-zA-Z-_]+:/" url))) "http://") url))
@ -75,3 +80,10 @@
[re-frame/trim-v]
(fn [{:keys [db now] :as cofx} [options]]
{:db (update db :browser/options merge options)}))
(handlers/register-handler-fx
:remove-browser
[re-frame/trim-v]
(fn [{:keys [db]} [browser-id]]
{:db (update-in db [:browser/browsers] dissoc browser-id)
:remove-browser browser-id}))

View File

@ -403,3 +403,9 @@
:request-permissions
(fn [_ [_ permissions then else]]
{::request-permissions-fx [permissions then else]}))
(handlers/register-handler-db
:set-swipe-position
[re-frame/trim-v]
(fn [db [item-id value]]
(assoc-in db [:chat-animations item-id :delete-swiped] value)))

View File

@ -0,0 +1,35 @@
(ns status-im.ui.screens.home.animations.responder
(:require [status-im.ui.components.react :as react]
[re-frame.core :as re-frame]
[status-im.ui.components.animation :as animation]))
(defn get-updated-value [gesture end-offset-x swiped?]
(let [base-value (if swiped? end-offset-x 0)]
(- base-value (.-dx gesture))))
(defn on-start [_ gesture]
(> (js/Math.abs (.-dx gesture)) 10))
(defn on-move [animated-offset-x end-offset-x swiped?]
(fn [_ gesture]
(let [to-value (get-updated-value gesture end-offset-x swiped?)]
(animation/start (animation/spring animated-offset-x {:toValue to-value})))))
(defn on-release [animated-offset-x end-offset-x chat-id swiped?]
(fn [_ gesture]
(let [updated-value (get-updated-value gesture end-offset-x swiped?)
should-open? (> updated-value (/ end-offset-x 2))
to-value (if should-open? end-offset-x 0)]
(re-frame/dispatch [:set-swipe-position chat-id should-open?])
(animation/start (animation/spring animated-offset-x {:toValue to-value})))))
(defn swipe-pan-responder [animated-offset-x end-offset-x chat-id swiped?]
(.create react/pan-responder
(clj->js {:onMoveShouldSetPanResponder on-start
:onPanResponderMove (on-move animated-offset-x end-offset-x swiped?)
:onPanResponderRelease (on-release animated-offset-x end-offset-x chat-id swiped?)
:onPanResponderTerminate (on-release animated-offset-x end-offset-x chat-id swiped?)})))
(defn pan-handlers [pan-responder]
(js->clj (.-panHandlers pan-responder)))

View File

@ -3,6 +3,8 @@
(:require [status-im.ui.components.styles :as component.styles]
[status-im.ui.components.colors :as colors]))
(def delete-button-width 100)
(defn toolbar []
{:background-color colors/white})
@ -202,4 +204,18 @@
(def toolbar-logo
{:size 42
:icon-size 17
:shadow? false})
:shadow? false})
(def delete-icon-highlight
{:position :absolute
:top 0
:bottom 0
:right -800
:width 800
:background-color colors/red-light})
(def delete-icon-container
{:flex 1
:width delete-button-width
:justify-content :center
:align-items :center})

View File

@ -10,6 +10,9 @@
[status-im.ui.components.sync-state.offline :refer [offline-view]]
[status-im.ui.screens.home.views.inner-item :as inner-item]
[status-im.ui.screens.home.styles :as styles]
[status-im.ui.components.icons.vector-icons :as vector-icons]
[status-im.ui.components.animation :as animation]
[status-im.ui.screens.home.animations.responder :as responder]
[status-im.utils.platform :as platform]
[status-im.react-native.resources :as resources]
[status-im.ui.components.common.common :as components.common]
@ -31,14 +34,24 @@
:accessibility-label :plus-button
:on-press #(re-frame/dispatch [:navigate-to :new])}])
(defn- home-list-item [[home-item-id home-item]]
(if (:chat-id home-item)
[react/touchable-highlight {:on-press #(re-frame/dispatch [:navigate-to-chat home-item-id])}
[react/view
[inner-item/home-list-chat-item-inner-view home-item]]]
[react/touchable-highlight {:on-press #(re-frame/dispatch [:open-browser home-item])}
[react/view
[inner-item/home-list-browser-item-inner-view home-item]]]))
(views/defview home-list-deletable [[home-item-id home-item]]
(views/letsubs [swiped? [:delete-swipe-position home-item-id]]
(let [delete-action (if (:chat-id home-item) :remove-chat :remove-browser)
inner-item-view (if (:chat-id home-item)
inner-item/home-list-chat-item-inner-view
inner-item/home-list-browser-item-inner-view)
offset-x (animation/create-value (if swiped? styles/delete-button-width 0))
swipe-pan-responder (responder/swipe-pan-responder offset-x styles/delete-button-width home-item-id swiped?)
swipe-pan-handler (responder/pan-handlers swipe-pan-responder)]
[react/view swipe-pan-handler
[react/animated-view {:style {:flex 1 :right offset-x}}
[inner-item-view home-item]
[react/touchable-highlight {:style styles/delete-icon-highlight
:on-press #(do
(re-frame/dispatch [:set-swipe-position home-item-id false])
(re-frame/dispatch [delete-action home-item-id]))}
[react/view {:style styles/delete-icon-container}
[vector-icons/icon :icons/delete {:color colors/red}]]]]])))
;;do not remove view-id and will-update or will-unmount handlers, this is how it works
(views/defview welcome [view-id]
@ -70,7 +83,7 @@
:else
[list/flat-list {:data home-items
:render-fn (fn [[home-item-id :as home-item]]
^{:key home-item-id} [home-list-item home-item])}])
^{:key home-item-id} [home-list-deletable home-item])}])
(when platform/android?
[home-action-button])
[offline-view]]))

View File

@ -1,8 +1,8 @@
(ns status-im.ui.screens.home.views.inner-item
(:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [clojure.string :as str]
(:require [re-frame.core :as re-frame]
[clojure.string :as str]
[status-im.ui.components.react :as react]
[status-im.ui.components.icons.vector-icons :as vector-icons]
[status-im.ui.screens.home.styles :as styles]
[status-im.ui.components.styles :as component.styles]
[status-im.utils.core :as utils]
@ -11,6 +11,7 @@
[status-im.utils.datetime :as time]
[status-im.utils.gfycat.core :as gfycat]
[status-im.constants :as const]
[status-im.ui.components.icons.vector-icons :as vector-icons]
[status-im.ui.components.chat-icon.screen :as chat-icon.screen]))
(defn message-content-text [{:keys [content] :as message}]
@ -87,38 +88,41 @@
public-key unremovable? :as chat]}]
(letsubs [last-message [:get-last-message chat-id]]
(let [name (or (i18n/get-contact-translated chat-id :name name)
(gfycat/generate-gfy public-key))]
[react/view styles/chat-container
[react/view styles/chat-icon-container
[chat-icon.screen/chat-icon-view-chat-list chat-id group-chat name color online]]
[react/view styles/chat-info-container
[react/view styles/item-upper-container
[chat-list-item-name name group-chat public? public-key]
(when last-message
[react/view styles/message-status-container
[message-status chat last-message]
[message-timestamp last-message]])]
[react/view styles/item-lower-container
[message-content-text last-message]
[unviewed-indicator chat-id]]]])))
(gfycat/generate-gfy public-key))]
[react/view
[react/touchable-highlight {:on-press #(re-frame/dispatch [:navigate-to-chat chat-id])}
[react/view styles/chat-container
[react/view styles/chat-icon-container
[chat-icon.screen/chat-icon-view-chat-list chat-id group-chat name color online]]
[react/view styles/chat-info-container
[react/view styles/item-upper-container
[chat-list-item-name name group-chat public? public-key]
(when last-message
[react/view styles/message-status-container
[message-status chat last-message]
[message-timestamp last-message]])]
[react/view styles/item-lower-container
[message-content-text last-message]
[unviewed-indicator chat-id]]]]]])))
(defview home-list-browser-item-inner-view [{:keys [browser-id name url dapp? contact] :as browser}]
(letsubs [contact' [:contact-by-identity contact]]
[react/view styles/chat-container
[react/view styles/chat-icon-container
(if contact'
[chat-icon.screen/dapp-icon-browser contact' 36]
[react/view styles/browser-icon-container
[vector-icons/icon :icons/discover {:color component.styles/color-light-gray6}]])]
[react/view styles/chat-info-container
[react/view styles/item-upper-container
[react/view styles/name-view
[react/view {:flex-shrink 1}
[react/text {:style styles/name-text
[react/touchable-highlight {:on-press #(re-frame/dispatch [:open-browser browser])}
[react/view styles/chat-container
[react/view styles/chat-icon-container
(if contact'
[chat-icon.screen/dapp-icon-browser contact' 36]
[react/view styles/browser-icon-container
[vector-icons/icon :icons/discover {:color component.styles/color-light-gray6}]])]
[react/view styles/chat-info-container
[react/view styles/item-upper-container
[react/view styles/name-view
[react/view {:flex-shrink 1}
[react/text {:style styles/name-text
:number-of-lines 1}
name]]]]
[react/view styles/item-lower-container
[react/view styles/last-message-container
[react/text {:style styles/last-message-text
:number-of-lines 1}
name]]]]
[react/view styles/item-lower-container
[react/view styles/last-message-container
[react/text {:style styles/last-message-text
:number-of-lines 1}
(or url (i18n/label :t/dapp))]]]]]))
(or url (i18n/label :t/dapp))]]]]]]))

View File

@ -50,4 +50,9 @@
(reg-sub :can-navigate-back?
(fn [db]
(> (count (:navigation-stack db)) 1)))
(> (count (:navigation-stack db)) 1)))
(reg-sub :delete-swipe-position
(fn [db [_ item-id]]
(let [item-animation (get-in db [:chat-animations item-id])]
(if (some? item-animation) (:delete-swiped item-animation) nil))))