com.pocketsoap.convodroid.AuthorMessageFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.pocketsoap.convodroid.AuthorMessageFragment.java

Source

// Copyright (c) 2012 Simon Fell
//
// Permission is hereby granted, free of charge, to any person obtaining a 
// copy of this software and associated documentation files (the "Software"), 
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, 
// and/or sell copies of the Software, and to permit persons to whom the 
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included 
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
// THE SOFTWARE.
//

package com.pocketsoap.convodroid;

import java.util.*;

import org.codehaus.jackson.type.TypeReference;

import android.app.Activity;
import android.graphics.*;
import android.os.Bundle;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import android.text.*;
import android.text.method.LinkMovementMethod;
import android.text.style.*;
import android.util.Log;
import android.view.*;
import android.view.View.OnClickListener;
import android.widget.*;

import com.actionbarsherlock.app.SherlockFragment;
import com.pocketsoap.convodroid.data.*;
import com.pocketsoap.convodroid.http.ChatterRequests;
import com.pocketsoap.convodroid.loaders.JsonLoader;
import com.salesforce.androidsdk.app.ForceApp;
import com.salesforce.androidsdk.rest.*;
import com.salesforce.androidsdk.rest.ClientManager.LoginOptions;
import com.salesforce.androidsdk.rest.ClientManager.RestClientCallback;

/**
 * @author @superfell
 *
 */
public class AuthorMessageFragment extends SherlockFragment implements OnClickListener, RestClientCallback {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.author, container, false);
        sendButton = (Button) v.findViewById(R.id.send_button);
        sendButton.setOnClickListener(this);
        sendButton.setEnabled(false);
        recipientText = (AutoCompleteTextView) v.findViewById(R.id.recipient_name);
        recipientText.setEnabled(false);
        recipientText.addTextChangedListener(new CompletionTextWatcher());
        recipients = (TextView) v.findViewById(R.id.recipients);
        recipients.setMovementMethod(LinkMovementMethod.getInstance());
        messageText = (EditText) v.findViewById(R.id.msg_body);
        messageText.addTextChangedListener(new EnablingTextWatcher());
        return v;
    }

    private UserSearchAdapter userAdapter;
    private Button sendButton;
    private AutoCompleteTextView recipientText; // current recipient being entered/selected.
    private TextView recipients; // list of actually selected recipients.
    private EditText messageText;
    private RestClient client;

    @Override
    public void onResume() {
        super.onResume();

        // Login options
        String accountType = ForceApp.APP.getAccountType();
        LoginOptions loginOptions = new LoginOptions(null, // login host is chosen by user through the server picker 
                ForceApp.APP.getPasscodeHash(), getString(R.string.oauth_callback_url),
                getString(R.string.oauth_client_id), new String[] { "api" });

        // Get a rest client
        new ClientManager(getActivity(), accountType, loginOptions).getRestClient(getActivity(), this);
    }

    @Override
    public void authenticatedRestClient(RestClient client) {
        if (userAdapter == null) {
            userAdapter = new UserSearchAdapter(getActivity(), client);
            recipientText.setAdapter(userAdapter);
            recipientText.setEnabled(true);
        }
        this.client = client;
    }

    @Override
    public void onClick(View v) {
        Log.i("Convodroid", "send " + messageText.getText() + " to " + recipients.getText());
        Spannable r = (Spannable) recipients.getText();
        sendButton.setEnabled(false);
        UserSpan[] users = r.getSpans(0, r.length(), UserSpan.class);
        List<String> recipients = new ArrayList<String>(users.length);
        for (UserSpan us : users)
            recipients.add(us.user.id);
        NewMessage m = new NewMessage();
        m.recipients = recipients;
        m.body = messageText.getText().toString();
        final RestRequest req = ChatterRequests.postMessage(m);
        getLoaderManager().restartLoader(0, null, new LoaderCallbacks<String>() {

            @Override
            public Loader<String> onCreateLoader(int id, Bundle args) {
                return new JsonLoader<String>(getActivity(), client, req, new TypeReference<String>() {
                });
            }

            @Override
            public void onLoadFinished(Loader<String> loader, String val) {
                getActivity().setResult(Activity.RESULT_OK);
                getActivity().finish();
            }

            @Override
            public void onLoaderReset(Loader<String> loader) {
            }
        });
    }

    static class UserSpan {

        UserSpan(User u) {
            assert u != null;
            this.user = u;
        }

        final User user;
    }

    private void updateSendButtonEnabled() {
        sendButton.setEnabled(recipients.getText().length() > 0 && messageText.getText().length() > 0);
    }

    // updated the enabled state of the end button after a text change.
    private class EnablingTextWatcher implements TextWatcher {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
        }

        @Override
        public void afterTextChanged(Editable s) {
            updateSendButtonEnabled();
        }
    }

    // this watches for the text to have a userId span in it (from the auto completion selection) and move it to the selected recipients list.
    private class CompletionTextWatcher extends EnablingTextWatcher {

        @Override
        public void afterTextChanged(Editable s) {
            UserSpan[] userSpans = s.getSpans(0, s.length(), UserSpan.class);
            if (userSpans != null && userSpans.length > 0) {
                if (recipients.length() > 0)
                    recipients.append("   ");
                SpannableString u = new SpannableString(s.toString() + " ");
                int len = u.length();
                u.setSpan(userSpans[0], 0, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                u.setSpan(new StyleSpan(Typeface.BOLD), 0, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                u.setSpan(new ForegroundColorSpan(Color.BLUE), 0, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                u.setSpan(new ImageSpan(getActivity(), R.drawable.remove, ImageSpan.ALIGN_BOTTOM), len - 1, len,
                        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                u.setSpan(new RemoveItemClickableSpan(userSpans[0]), 0, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                recipients.append(u);
                s.clear();
            }
            super.afterTextChanged(s);
        }
    }

    private class RemoveItemClickableSpan extends ClickableSpan {

        RemoveItemClickableSpan(UserSpan user) {
            this.user = user;
        }

        private final UserSpan user;

        @Override
        public void updateDrawState(TextPaint ds) {
            // we don't want to change the text appearance.
        }

        @Override
        public void onClick(View widget) {
            TextView tv = (TextView) widget;
            Spanned span = (Spanned) tv.getText();
            int start = span.getSpanStart(user);
            if (start == -1)
                return;
            int end = span.getSpanEnd(user);
            tv.getEditableText().delete(start, end);
        }
    }
}