Android-stories: A simple stories library inspired by Instagram and alike

Related tags

App android-stories
Overview

Android-stories

Platform license

open and closetemplates

A simple stories library inspired by Instagram and alike.

Requirements

  • Min SDK >= 22

Installation

Add these dependencies to your project:

repositories {
    maven { url 'https://jitpack.io' }
}

dependencies {
    implementation 'com.github.redmadrobot-tomsk:android-stories:1.1.1'
}

Initialization

  1. Initialize StoriesCacheFactory in your Application class.
class App : Application() {
    override fun onCreate() {
        super.onCreate()
        StoriesCacheFactory
            .init(this, CoroutineScope(Dispatchers.IO + SupervisorJob()))
            .preloadImages(false)
            .setConfig(StoriesConfig.All)
    }
}
  1. Add internet permission to your manifest for Glide.
">

Setting up stories activity

  1. Extend StoriesBaseActivity and override its functions how you see fit. Note that you MUST start stories activity with intent returned by StoriesBaseActivity.newStoriesIntent because of required parameters (StoriesInputParams). Otherwise, exception will be thrown.
class StoriesActivity : StoriesBaseActivity() {

    companion object {
        fun newIntent(
            context: Context,
            storiesInputParams: StoriesInputParams
        ): Intent = newStoriesIntent(
            context = context,
            clazz = StoriesActivity::class.java,
            storiesInputParams = storiesInputParams
        )
    }
    
    override fun onStoryActionClicked(url: String) {
        // TODO: Your implementation.
    }

    override fun closeStories() {
        super.closeStories()
    }

    override fun onCompleteStory() {
        super.onCompleteStory()
    }

    override fun hasPreviousStory(story: Story): Boolean {
        return super.hasPreviousStory(story)
    }
}
  1. Create stories models (e.g. by fetching from your API and converting). For example, here is a simple story model:
val story = Story(
    id = "some-UUID-or-else",
    name = "story name",
    isSeen = false,
    previewUrl = "https://your-api.com/preview-image-url",
    title = "title",
    frames = listOf(
        StoryFrame(
            imageUrl = "https://your-api.com/frame-image-url",
            content = StoryFrameContent(
                controlsColor = StoryFrameControlsColor.DARK, // Color for progress and close button.
                showGradients = StoryFrameShowGradients.BOTTOM, // Where to show gradient.
                position = StoryFrameContentPosition.TOP, // Position of contents relative to the StoryFrame.
                textColor = "#FFFFFF",
                header1 = "First story frame header",
                header2 = "Second story frame header",
                descriptions = listOf("First line of description", "Second line of description"),
                action = StoryFrameAction(
                    text = "Text to be displayed on clickable action button",
                    url = "https://your-api.com/deep-link-or-url"
                ),
                gradientColor = "#000000"
            )
        )
    )
)
  1. Add stories to StoriesController.
val stories = listOf(story) // sample story was created in  p.2
val controller: StoriesController = StoriesCacheFactory.getInstance()
controller.clearAndAdd(StoriesConfig.All, stories)
  1. Start StoriesActivity (don't forget to add required arguments to intent).
someButton.setOnClickListener {
    val intent = StoriesActivity.newIntent(
        context = this,
        storiesInputParams = StoriesInputParams.createDefaults()
    )
    startActivity(intent)
}

Setting up previews

  1. Add RecyclerView to your activity/fragment layout that should open StoriesActivity.
">


    
    

    

    


  1. In your activity/fragment (e.g. MainActivity), create stories previews adapter, assign it to the RecyclerView, and implement StoriesAdapterListener interface to open StoriesActivity ( see "Setup Stories activity" section).
class MainActivity : AppCompatActivity(), StoriesBasePreviewAdapter.StoriesAdapterListener {

    private val storiesAdapter = StoriesPreviewAdapter(this@MainActivity)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        findViewById(R.id.recyclerStories).adapter = storiesAdapter
    }

    override fun onStoryClicked(storiesInputParams: StoriesInputParams) {
        val intent = StoriesActivity.newIntent(
            context = this,
            storiesInputParams = storiesInputParams
        )
        startActivity(intent)
    }
}

(note that you can create your own stories previews adapter by extending StoriesBasePreviewAdapter).

Custom story frame view

It's possible to use a different story frame layout if you wish to change it. StoryFrameViewImpl is used by default.

  1. Create your own story frame view by extending BaseStoryFrameView. You should set data to your views and update them in onFrameSet.
class CustomStoryFrameView(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : BaseStoryFrameView(context, attrs, defStyleAttr) {

    init {
        View.inflate(context, R.layout.view_custom_frame, this)
    }

    private val textTitle = findViewById(R.id.textTitle)

    override fun onFrameSet(frame: StoryFrame) {
        textTitle.text = frame.content.header1
    }
}

view_custom_story.xml:

">



    


  1. Extend StoryFragment and override createStoryFrameView, where you should return your BaseStoryFrameView implementation. Note that you MUST pass story instance when creating your custom fragment by calling StoryFragment#addStoryToArguments, otherwise, exception will be thrown (similar to StoriesBaseActivity and StoriesInputParams).
class CustomStoryFragment : StoryFragment() {
    companion object {
        fun newInstance(story: Story): StoryFragment =
            CustomStoryFragment().addStoryToArguments(story)
    }

    override fun createStoryFrameView(context: Context): BaseStoryFrameView =
        CustomStoryFrameView(context)
}
  1. Override createStoriesFragment in your stories activity derived from StoriesActivity like this:
class StoriesActivity : StoriesBaseActivity() {
    override val createStoriesFragment: ((Story) -> StoryFragment) = { story ->
        CustomStoryFragment.newInstance(story)
    }
}
  1. You can change the behaviour of "is seen" status for the story by passing StoryIsSeenWhen to StoryFragment#addToStoryArguments. See StoryIsSeenWhen for more details.
class StoriesActivity : StoriesBaseActivity() {
    override val createStoryFragment: ((Story) -> StoryFragment) = { story ->
        StoryFragment.newStoryFragmentInstance(story, StoryIsSeenWhen.TWO)
    }
}

For more info, see the example .

License

The library is distributed under the MIT LICENSE. See LICENSE for details.

You might also like...
E- commerce app👕  built with Jetpack Compose and Compose Destinations. The design was inspired by Sajjad Mohammadi Nia
E- commerce app👕 built with Jetpack Compose and Compose Destinations. The design was inspired by Sajjad Mohammadi Nia

E-Commerce Clothing App 👕 This a Jetpack Compose app that replicates of an E-commerce app design I was inspired by on Dribble. It's an E-Commerce app

This project is an android app inspired by the tv show
This project is an android app inspired by the tv show "Friends"

F.R.I.E.N.D.S-App If this frame looks familiar then this app is for you! This project is an android app inspired by the tv show "Friends" , built usin

RedditVanced - Reddit Android app mod inspired by Aliucord

RedditVanced A rootless a Reddit android app mod ⚠️ NOTE ⚠️ This project is curr

Android app inspired by NASA APOD Api
Android app inspired by NASA APOD Api

MVVM - Clean Architecture - Kotlin - Retrofit - Room - Dagger Hilt - Coroutines - Flow - Coil - Navigation Component

Implementation of useful hooks inspired by React for Compose
Implementation of useful hooks inspired by React for Compose

useCompose React inspired hooks for Compose Installation Step 1. Add the JitPack repository to your build file Add it in your root build.gradle at the

Not so deep text reader inspired by BORIS, written in Kotlin

Barnable Reader Prototype Deep text reader library that generates a semantic model from a short input text. At the moment it is very primitive and is

A Discord bot heavily inspired by Ultimate Bravery to spice up your Pokemon Unite experience.

UniteBraveryBot 🎲 A Discord bot heavily inpired by Ultimate Bravery to spice up your Pokemon Unite experience. Required Permissions 🧰 View Channels

A simple and easy to use stopwatch and timer library for android

TimeIt Now with Timer support! A simple and easy to use stopwatch and timer library for android Introduction A stopwatch can be a very important widge

Simple-todo-app - Simple Memo App using SQLite

Judul Aplikasi Aplikasi Memo Sederhana menggunakan SQLite. Fitur Aplikasi Memo y

Comments
  • Customize stories feature

    Customize stories feature

    В данном issue будут описаны предложения/исследования фичи кастомизации сторисов.

    Сначала нужно определиться с необходимыми вьюхами у сториса. Для этого, ниже приведены иерархия вьюх в уже готовых лэйаутах.

    • Сторис StoryFragment:
    • Прогресс бар сториса (StoriesProgressView)
    • Кнопка закрытия (ImageView/Button)
    • Фрейм истории (StoryFrameView)

    Фрейм сториса StoryFrameView:

    • Картинку фрейма (ImageView)
    • Контент фрейма (StoryFrameContentView)
    • Прогресс бар загрузки фрейма (ProgressBar)
    • Лэйаут ошибки (View) - кнопка перезагрузки, обязателен коллбек onRefresh

    Контент фрейма StoryFrameContentView:

    • Заголовок (TextView)
    • Подзаголовок (TextView)
    • Подробное описание (TextView)
    • Кнопка действия (Button) - должен быть onClick

    Следовательно, у сториса следующие основные элементы:

    • Прогресс бар
    • Картинка фрейма
    • Текст фрейма (заголовок, подзаголовок, подробнее)
    • Кнопка фрейма (обработка юрла по клику)
    • Вью ошибки

    Нужно добавить возможность замены имеющихся лэйаутов сторисов/фреймов/контента на свой собственный. Другой вопрос - как вставить собственные лэйауты в StoryFragment. Как вариант, можно передавать в конструктор StoryFragment указанные выше вьюхи. К примеру:

    class StoryFragment : Fragment(), StoryListener {
        companion object {
            fun newInstance(story: Story, views: StoryViews): Fragment {
                ...
                return StoryFragment()
            }
        }
    }
    
    // Все основные элементы сториса
    data class StoryViews(
        val progressBar: StoriesProgressView,
        val image: ImageView,
        val title: TextView,
        val subTitle: TextView,
        val description: TextView,
        val button: Button?,
        val errorView: View
    )
    

    Довольно простой способ, но тогда не получится управлять расположением элементов. По-хорошему, надо передавать именно R.layout.my_layout, но тогда, скорее всего, придется проверять наличие всех элементов в рантайме и выкидывать эксепшн при отсутствии.

    Если ничего не пропускаю, реализация коллбэков типа нажатия кнопки сторисов уже реализована (добавлять кастомизацию и для этого было бы еще труднее), поэтому надо сначала решить с вьюхами.

    Следующий вопрос - когда добавлять кастомные вьюхи. StoryFragment создается в FragmentAdapter-е, так что, скорее всего, вьюхи/лэйаут надо передать именно в него.

    В итоге, нужно подумать о следующих моментах:

    1. Как добавлять кастомные вьюхи - передавать инстансы в конструктор или передавать лэйаут? Во втором случае, как создать контракт о необходимых вью?
    2. Когда совершить замену вьюх на кастомные? Скорее всего, передачу можно делать при инициализации либы, а эти вьюхи/лэйаут будут передаваться при создании фрагмента (в fragment adapter).
    3. Надо определиться с максимальным минимумом необходимых вьюх. Потенциально, могут не понадобиться заголовки сторисов, соответственно, и в лэйауте вьюхи с текстом требовать не надо.
    opened by MichaelMaltsev 6
  • Add custom story frame support

    Add custom story frame support

    Сделал реализацию кастомных фреймов сторисов, схема такая: В активити сторисов, которая наследуется от StoriesBaseActivity, надо оверрайднуть createStoriesFragment:

    class CustomStoriesActivity : StoriesBaseActivity() {
        override val createStoriesFragment: ((Story) -> StoryFragment) = { story ->
            CustomStoryFragment.newInstance(story)
        }
    }
    

    Уже в фрагменте указываем кастомную вьюху:

    class CustomStoryFragment : StoryFragment() {
        companion object {
            fun newInstance(story: Story): StoryFragment =
                CustomStoryFragment().addStoryToArguments(story)
        }
    
        override fun createStoryFrameView(context: Context): BaseStoryFrameView =
            CustomStoryFrameView(context)
    }
    

    Важный момент по поводу newInstance, пришлось сделать аналогично обязательным параметрам в StoriesBaseActivity, где если не вызываем метод компаньона у родительского класса с передачей аргумента, то выбрасывается соответствующий эксепшн.

    Наконец, сама кастомная вьюха фрейма:

    class CustomStoryFrameView(context: Context) : BaseStoryFrameView(context) {
    
        private val binding = ViewCustomStoryFrameBinding.inflate(LayoutInflater.from(context)).apply {
            addView(root)
        }
    
        override fun onFrameSet(frame: StoryFrame) {
            binding.textTitle.text = frame.content.header1
    
            binding.image.setImageWithGlide(
                imageUrl = frame.imageUrl,
                onReady = { listener?.onLoaded() },
                onFailed = { binding.textError.isVisible = true }
            )
        }
    }
    

    onFrameSet - это коллбэк метод, вызываемый при задании нового фрейма, в нем нужно обновлять фрейм.

    Описанный выше код взят из примера, который так же есть в этом ПР-е.

    В итоге получилось средней сложности, но все равно хотелось бы идеального мира, где можно было бы просто передать в конструктор/билдер кастомную вьюху...

    feature 
    opened by MichaelMaltsev 1
  • Add

    Add "is seen" configuration to input params

    Вышло не очень юзер-френдли, но настройка статуса "просмотрено" делается через передачу аргумента во фрагмент:

    class CustomStoryFragment : StoryFragment() {
        companion object {
            fun newInstance(story: Story): StoryFragment =
                CustomStoryFragment().addStoryToArguments(story, StoryIsSeenWhen.TWO)
        }
    
    feature 
    opened by MichaelMaltsev 0
Owner
red_mad_robot Tomsk
red_mad_robot Tomsk
Monster Hunter Stories Gene App

MHGene 魔物獵人:物語2 基因模擬器 Google Play Store : https://play.google.com/store/apps/details?id=com.solinari.MHSGene 還在基因配置煩惱? 還在用紙筆規劃嗎? 鄭重推出沒有廣告,超佛心的基因模擬器! 輕

Solinari 4 Nov 5, 2021
Kalam is an app that gives people a chance to write their stories on the app.

Kalam is an app that gives people a chance to write their stories on the app. This app gives a good story for the story readers and gives good story writers a chance to write their own story

Uday Chugh 0 Apr 26, 2022
📦📦Video downloader for Android - Download videos from Youtube, Facebook, Twitter, Instagram, Dailymotion, Vimeo and more than 1000 other sites

youtube-dl-android ?? An Android client for youtube-dl: https://github.com/rg3/youtube-dl Major technologies Language: Kotlin Architecture: MVVM Andro

Cuong Pham 445 Jan 8, 2023
Instagram clone App in android using Kotlin, LiveData, MVVM, Dagger, RxJava and Retrofit.

Instagram-Project-in-android-with-MVVM-architecture Project from MindOrks Professional Bootcamp with self practice work and added some additional feat

Abhishek Solanki 3 Feb 28, 2022
Implementation of Instagram with Material Design (originally based on Emmanuel Pacamalan's concept)

InstaMaterial Updated Current source code contains UI elements from Design Support Library. If you still want to see how custom implementations of e.g

Mirosław Stanek 5k Dec 27, 2022
A minimalist clone of the popular Social Media Platform "Instagram"

InstaLocal A minimalist clone of the popular Social Media Platform "Instagram" powered by Firebase and written in Kotlin. The app allows users to sign

Raktim Bhuyan 1 Nov 7, 2021
KotinInstagramClone - Kotlin Instagram Clone

Kotin Instagram Clone Bu uygulamayı yazarken çeşitli kaynaklardan yardım alarak

Yakup Üstüner 0 Feb 2, 2022
A clone of Instagram I made with Firebase.

InstagramClone In this project, I made an Instagram clone. I used firebase auth, firestore database and storage, I wrote it according to mvvm architec

Süveybe Sena Küçük 15 Dec 1, 2022
Instagram-like story editor in compose

Story Editor Instagram-like story editor to add content to your pictures. Note: this is still a WIP Setup First, add jitpack in your build.gradle at t

Yann Badoual 27 Nov 30, 2022
Simple timer app inspired by Newton's Cradle. Created in Jetpack Compose for #AndroidDevChallenge.

Newton's Timer ?? Description Simple timer app inspired by Newton's Cradle. Created in Jetpack Compose for #AndroidDevChallenge. ?? Motivation and Con

Maciej Ciemięga 278 Dec 28, 2022