Git Product home page Git Product logo

android-ago's Introduction

android-ago

This library provides RelativeTimeTextView, a custom TextView that takes a reference time and always displays the relative time with respect to the reference point, automatically refreshing the display text as needed. This is a common pattern seen in several apps like chat apps, social networking, email etc.

Here is a screenshot from the sample app

This library can be seen as a wrapper on top of the excellent android.text.format.DateUtils class. Note that the library does not expose all the options provided by the DateUtils class. I have left out many features because I couldn't decide what would be the best way to achieve the flexibility - dozens of XML attributes? Contributions in this regard are welcome.

Why should I use this instead of DateUtils class?

Because this library automatically refreshes the display text as needed. It internally uses DateUtils class.

Imagine you use DateUtils directly without using this library.

  • Imagine that it is 9 am now. You set a reference time of 9:05 am. Your TextView displays in 5 mins
  • Now the time becomes 9:01 am. You still display in 5 mins even though you should be showing in 4 mins

To do this correctly, you will need to keep refreshing the text views every minute. However, even that is not necessary. If the reference time is 3 hours from now, you only need to refresh every hour - not every minute.

This library handles all of this for you. RelativeTimeTextView automatically refreshes the display text only as often as necessary.

Obtaining

Gradle

Add the following to your build.gradle

dependencies {
    compile 'com.github.curioustechizen.android-ago:library:1.4.0'
}

Important: v1.3.4 Fixed a major bug (#47). If you are using an older version, please update to at least 1.3.4 now.

Eclipse+ADT

  1. Clone the repo
  2. In Eclipse, go to File -> New -> Other. Expand Android and select Android Project from Existing Code
  3. Browse to the android-ago sub-folder of the cloned repo and hit Finish

Usage

  • Include RelativeTimeTextView in your layouts.
  • Set the reference time either using setReferenceTime method or using the XML attribute reference_time.

In your layout:

<com.github.curioustechizen.ago.RelativeTimeTextView
    android:id="@+id/timestamp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="@dimen/margin_primary" />

In your Java code:

RelativeTimeTextView v = (RelativeTimeTextView)findViewById(R.id.timestamp); //Or just use Butterknife!
v.setReferenceTime(new Date().getTime());

See the sample project for a concrete example.

Customization

By default, this library simply calls DateUtils.getRelativeTimeSpanString. This might not be sufficient for you. For example, you might need to add a prefix. RTTV provides a hook for such cases - the getRelativeTimeDisplayString method. You can override this method and add whatever prefixes or suffixes you need.

Here is a simple example:

<!-- strings.xml -->
<string name="format_relative_time_with_prefix">Updated %1$s</string>
class PrefixRttv extends RelativeTimeTextView {
    @Override
    protected CharSequence getRelativeTimeDisplayString(long referenceTime, long now) {
        final String relativeTime = super.getRelativeTimeDisplayString(referenceTime, now);
        return getResources.getString(R.string.format_relative_time_with_prefix, relativeTime);
    }    
}

More examples in the sample project

Advanced customization

What if the string returned by DateUtils.getRelativeTimeSpanString does not suit you? Well, you can still use RTTV for its auto-refresh capability and take over complete control of the display string itself. Simply override getRelativeTimeDisplayString and don't call through to the super method. Instead, perform your own logic and return whatever string you wish here.

<!-- strings.xml -->
<string name="future">Some day, in the distance future</string>
<string name="past">Once upon a time, long long ago</string>
<string name="now">Right NOW!</string>
class FullyCustomRttv extends RelativeTimeTextView {
    @Override
    protected CharSequence getRelativeTimeDisplayString(long referenceTime, long now) {
        //Notice that we don't call super here.
        int resourceId = 0;
        if(referenceTime == now) resourceId = R.id.now;
        else if(referenceTime > now) resourceId = R.id.future;
        else resourceId = past;
        
        return getResources().getString(resourceId);
    }    
}

See the examples in the sample project for more details.

Who's Using this Library?

See here. If you would like to add your app to this list, please edit the wiki.

Android version support statement

The library has been tested on API 11 and above. However, theoretically, it works on API 3 and above since all it uses is [DateUtils#getRelativeTimeSpanString](http://developer.android.com/reference/android/text/format/DateUtils.html#getRelativeTimeSpanString(long, long, long, int)).

The minSdkVersion has been set to 8, however do not expect support from me for API version < 11.

Usage with Data Binding

See android-ago-sample-databinding for an example of how to use this library with the Android data binding library. Thanks to @Dev-IL for providing this sample.

License

Copyright 2017 Kiran Rao

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

android-ago's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

android-ago's Issues

How to change Time text to custome one?

I want to change the Time's text to something like 5s, 5m instead of 5 seconds ago and 5 minutes ago.
I don't know where to change to custom text.

The reason i want to minimize is, it takes too much space when designing custom row layout.

Thanks,

Removing the "ago" word

Is there any way to remove the "ago" word from the RelativeTimeTextView?
To be more clear
for example if the RelativeTimeTextView is showing this String
"16 min. ago"
can I convert it to
"16 min."
this way is more user friendly ...you know shortest text is always better
thanks in advance

Refreshing of display text not accurate when view is recycled.

When a RelativeTimeTextView is included as part of a row item in a ListView or similar, the row item is recycled when the row goes off screen. When this happens, neither onVisibilityChanged() is called, nor onDetachedFromWindow(). As a result, the scheduled update of the display text continues according to the old value of reference time.

The correct behavior should be that when view recycling happens, the scheduled updates should happen according to the new value of reference time.

Add automated tests

Introduce an abstraction for getting time (instead of using System.currentTimeMillis()) directly in RTTV.

Build on top of this to add automated tests, especially around scheduling the UpdateTimeTask.

Feature request: Support for Data Binding

I'm building an app that relies heavily on data binding. I was trying to include an instance of RelativeTimeTextView with XML bindings for app:relative_time_prefix and app:reference_time - however this results in a compilation-time error:

Error:java.lang.RuntimeException: Found data binding errors.
        ****/ data binding error ****msg:Cannot find the setter for attribute 'app:relative_time_prefix' with parameter type java.lang.String.

I'm not sure if what's causing this is the fact attributes/fields aren't set as @Bindable or Observable.., or that the property setters aren't named like the binding expects (if I understand the Data Binding documentation correctly).

Needless to say that when I remove the bindings of these fields from my XML, the compilation succeeds.

It would be awesome if somebody could add this support - and help make the library more future-proof :)


I'm using the following XML (irrelevant portions removed):

<data>
    <variable name="message" type="..."/>
</data>
....
<com.github.curioustechizen.ago.RelativeTimeTextView
    android:id="@+id/time_n_sender"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="14sp"
    app:relative_time_prefix='@{"by " + message.senderName + ", "}'
    app:reference_time='@{message.timestamp}'
    tools:textColor="@color/gray"
    tools:text="by Mike, 30/02/2016 22:22:10"/>

P.S.
Does the format dd/MM/yyyy HH:mm:ss constitute a valid for app:reference_time?

setReferenceTime get "0 time ago"

When I set mReferenceTime lower than currentTimeMillis method getRelativeTimeDisplayString returned "0 time ago"
For example: I have mReferenceTime = 10, and currentTimeMillis = 8. Method getRelativeTimeDisplayString will be return "0 time ago"

Any ideas?

minSdkVersion?

The actual library says android:minSdkVersion="14" but the sample app has android:minSdkVersion="8".

Which is correct?

I'm trying to add Gradle build files and it won't compile without fixing this.

Time is one hour behind on old Galaxy Tab 3 using Android 4.4.2

HI and thanks for grate lib.
Using 'com.github.curioustechizen.android-ago:library:1.3.4' and XML looks like:

     <com.github.curioustechizen.ago.RelativeTimeTextView
                android:id="@+id/timestamp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginEnd="2dp"
                android:layout_marginRight="2dp"
                tools:text="Just Now"/>

The time is always one hour behind. The device clock is set correctly.
I am in Sweden btw. What do you think? In Sweden we have summer time adjustment that mean during summer time is set forward one hour. It feels like your lib dont take that into consideration since the time I see on the Galaxy tab 3 is normal European time(correct time) (but it will for me in Sweden be one our behind)( We do this time thing to get more daylight sunlight)
https://www.timeanddate.com/time/change/sweden/malmo

I have also a Galaxy Note 4 running android 6.0.1 and time is correct all ok

Locale

Is this library available in other languages?
if not are you planning to add this feature in the near future

note: I can help translate into Arabic

Add a `getReferenceTime()` method

It is an oversight that RTTV does not have a way to tell you what its current reference time is. Add a getReferenceTime() method.

in 0 mins

Seems to happen basically the moment a new item is added with timestamp = now, shortly after that, the value changes to "Just now" as expected

Add translations

Add translations for the string resources (currently, there's just a single string - "Just Now"). We have English and German strings at present.

this work fine in recyclerviews?

If you have 1000 items in a recyclerview, running 1000 threads every time?
Or it detects when the item is not displayed and thus ends its thread of execution

View "lifecycle" not handled correctly w.r.t handler that refreshes display text.

The method startTaskForPeriodicallyUpdatingRelativeTime() is called both in onAttachedToWindow() and in onVisibilityChanged(). This could result in the Runnable being scheduled twice.

This is because the first time the RelativeTimeTextView is added to its parent, both onAttachedToWindow() and onVisibilityChanged() are called (the latter is called for the parent Window).

Frequent IndexOutOfBoundsException

Fatal Exception: java.lang.IndexOutOfBoundsException
Invalid index 1, size is 1
java.util.ArrayList.throwIndexOutOfBoundsException (ArrayList.java:251)
java.util.ArrayList.get (ArrayList.java:304)
android.widget.TextView.sendAfterTextChanged (TextView.java:7119)
android.widget.TextView.setText (TextView.java:3574)
android.widget.TextView.setText (TextView.java:3425)
android.widget.TextView.setText (TextView.java:3400)
com.github.curioustechizen.ago.RelativeTimeTextView.updateTextDisplay (RelativeTimeTextView.java:146)
com.github.curioustechizen.ago.RelativeTimeTextView.access$200 (RelativeTimeTextView.java:22)
com.github.curioustechizen.ago.RelativeTimeTextView$UpdateTimeRunnable.run (RelativeTimeTextView.java:265)

Once the `UpdateTimeRunnable` is detached and the `weakRefRttv` cleared, it is never attached again

In the stopTaskForPeriodicallyUpdatingRelativeTime() method, the mUpdateTimeTask is detached, resulting in the weak reference that connects it the the RelativeTimeView being cleared. In the startTaskForPeriodicallyUpdatingRelativeTime() method, the same mUpdateTimeTask is reused, but the weak reference is still null. As a consequence, the run() method in the runnable cannot update the text view.

It should be pretty easy to reproduce. Any action that results in the stopTaskForPeriodicallyUpdatingRelativeTime() method being called should cause the time to stop being updated. For example, minimize the app and restore it.

Time ago calculation

Hello

why every time the calculations display "in 23 hours " what is the problem ?

Regards

Modify time update interval

I'm wanting to show ETAs that will commonly be less than 60 minutes but may occasionally be up to 120 minutes. In the case that the ETA is 60 minutes or less, the ETA text of my RelativeTextView updates every minute. In the case where an ETA is greater than 60 minutes, the ETA text updates every hour. However, I need the ETA to update every minute regardless of the difference between now and the reference time.

Current interval logic:

if (difference > DateUtils.WEEK_IN_MILLIS) {
   interval = DateUtils.WEEK_IN_MILLIS;
} else if (difference > DateUtils.DAY_IN_MILLIS) {
   interval = DateUtils.DAY_IN_MILLIS;
} else if (difference > DateUtils.HOUR_IN_MILLIS) {
   interval = DateUtils.HOUR_IN_MILLIS;
}

I think it would be helpful to add the ability to modify the time update interval. This could be achieved in a couple ways.
A) Add a public setter to set and override the time interval.
B) Allow subclasses to override the method that determines the interval.

I prefer option B as it provides more flexibility to the client.

@curioustechizen What are your thoughts on adding the ability to modify the time update interval?

Ad How to use to Readme

Am an Android newbie. please how do i add this to my project on android studio. I tried searching for the projects on Maven central but it was not there. Kindly add installation instructions to the readme.

Awesome plugin Btw.

RelativeTimeTextView and memory leaks

I think this library is causing some memory leaks - can you please fix?

I tested this with LeakCanary: https://github.com/square/leakcanary

And it keeps on detecting a memory leak here:

01-27 21:07:53.075 4217-4353/? D/LeakCanary: In com.example.simon.recyclerviewlistwithmongo:1.0:1.
01-27 21:07:53.075 4217-4353/? D/LeakCanary: * com.example.simon.activities.PostDetailActivity has leaked:
01-27 21:07:53.075 4217-4353/? D/LeakCanary: * GC ROOT android.view.ViewRootImpl$WindowInputEventReceiver.mMessageQueue
01-27 21:07:53.075 4217-4353/? D/LeakCanary: * references android.os.MessageQueue.mMessages
01-27 21:07:53.075 4217-4353/? D/LeakCanary: * references android.os.Message.callback
01-27 21:07:53.075 4217-4353/? D/LeakCanary: * references com.github.curioustechizen.ago.RelativeTimeTextView$UpdateTimeRunnable.this$0
01-27 21:07:53.075 4217-4353/? D/LeakCanary: * references com.github.curioustechizen.ago.RelativeTimeTextView.mContext
01-27 21:07:53.075 4217-4353/? D/LeakCanary: * references android.support.v7.view.ContextThemeWrapper.mBase
01-27 21:07:53.075 4217-4353/? D/LeakCanary: * leaks com.example.simon.activities.PostDetailActivity instance
01-27 21:07:53.075 4217-4353/? D/LeakCanary: * Reference Key: f949ab86-5469-40cf-9f6b-bae54f1eedfa
01-27 21:07:53.075 4217-4353/? D/LeakCanary: * Device: Genymotion generic Samsung Galaxy S2 - 4.1.1 - API 16 - 480x800 vbox86p
01-27 21:07:53.075 4217-4353/? D/LeakCanary: * Android Version: 4.1.1 API: 16 LeakCanary: 1.3.1
01-27 21:07:53.075 4217-4353/? D/LeakCanary: * Durations: watch=5009ms, gc=116ms, heap dump=259ms, analysis=9831ms

Suggest fix: Please replace the context that is passed in RelativeTimeTextView.mContext with an ApplicationContext.

Thanks!

Lack of consistent capitalization (English)

Description

Capitalization of the "Just Now" time text is inconsistent with the other English words and phrases used in this library.

Version

1.3.2

Severity

Minor

Steps to Reproduce

  1. Set a time on the RelativeTimeTextView.
  2. Observe the results as the time ages.

Actual behavior

The relative time text starts with "Just Now" and progresses to "1 min. ago", "Yesterday", "November 16", etc.

Expected behavior

The "Just Now" phrase is consistent with the other words/phrases used in this library. If the time text contains more than one word, I recommend capitalizing the first word and making the remaining words lowercase similar to today's "1 min. ago" format.

So "Just now" would become "Just now".

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.