├── .editorconfig
├── .github
├── CODEOWNERS
├── dependabot.yml
├── pull_request_template.md
└── workflows
│ └── android.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── FUNDING.yml
├── LICENSE
├── README.md
├── app
├── .gitignore
├── benchmark-rules.pro
├── build.gradle.kts
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── kotlin
│ └── io
│ └── getstream
│ └── chat
│ └── android
│ └── twitchclone
│ ├── MainActivity.kt
│ ├── TwitchCloneApp.kt
│ ├── initializer
│ ├── AssetsInitializer.kt
│ ├── MainInitializer.kt
│ ├── StreamChatInitializer.kt
│ ├── StreamLogInitializer.kt
│ └── StreamVideoInitializer.kt
│ ├── navigation
│ ├── NavSlideComposable.kt
│ ├── TwitchNavHost.kt
│ └── TwitchNavigation.kt
│ └── ui
│ └── TwitchCloneMain.kt
├── baselineprofile
├── .gitignore
├── build.gradle.kts
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── kotlin
│ └── io
│ └── getstream
│ └── chat
│ └── android
│ └── twitchclone
│ └── baselineprofile
│ └── BaselineProfileGenerator.kt
├── build-logic
├── convention
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ └── kotlin
│ │ ├── AndroidApplicationComposeConventionPlugin.kt
│ │ ├── AndroidApplicationConventionPlugin.kt
│ │ ├── AndroidFeatureConventionPlugin.kt
│ │ ├── AndroidHiltConventionPlugin.kt
│ │ ├── AndroidLibraryComposeConventionPlugin.kt
│ │ ├── AndroidLibraryConventionPlugin.kt
│ │ ├── SpotlessConventionPlugin.kt
│ │ └── io
│ │ └── getstream
│ │ └── chat
│ │ └── android
│ │ └── twitchclone
│ │ ├── AndroidCompose.kt
│ │ └── KotlinAndroid.kt
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
└── settings.gradle.kts
├── build.gradle.kts
├── buildSrc
├── build.gradle.kts
└── src
│ └── main
│ └── kotlin
│ └── io
│ └── getstream
│ └── chat
│ └── android
│ └── Configuration.kt
├── core-data
├── .gitignore
├── build.gradle.kts
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── kotlin
│ └── io
│ └── getstream
│ └── chat
│ └── android
│ └── twitchclone
│ └── data
│ ├── coroutines
│ └── WhileSubscribedOrRetained.kt
│ ├── di
│ └── DataModule.kt
│ ├── mapper
│ └── Mappers.kt
│ └── repository
│ ├── RewardRepository.kt
│ └── RewardRepositoryImpl.kt
├── core-database
├── .gitignore
├── build.gradle.kts
├── schemas
│ └── io.getstream.chat.android.twitchclone.database.TwitchDatabase
│ │ └── 1.json
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── kotlin
│ └── io
│ └── getstream
│ └── chat
│ └── android
│ └── twitchclone
│ └── database
│ ├── TwitchDatabase.kt
│ ├── dao
│ └── RewardDao.kt
│ ├── di
│ └── DatabaseModule.kt
│ └── entity
│ └── RewardEntity.kt
├── core-designsystem
├── .gitignore
├── build.gradle.kts
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ ├── badges
│ │ ├── cat.gif
│ │ ├── cat2.gif
│ │ ├── cool.gif
│ │ ├── gold.png
│ │ ├── prime.png
│ │ └── star.png
│ ├── emotes
│ │ ├── angelthump.png
│ │ ├── ariw.png
│ │ ├── brobalt.png
│ │ ├── bttvnice.png
│ │ ├── burself.png
│ │ ├── candianrage.png
│ │ ├── cigrip.png
│ │ ├── concerndoge.png
│ │ ├── cruw.png
│ │ ├── cvhazmat.png
│ │ ├── cvl.png
│ │ ├── cvmask.png
│ │ ├── cvr.png
│ │ ├── datsauce.png
│ │ ├── dogchamp.png
│ │ ├── duckerz.png
│ │ ├── feelsamazingman.png
│ │ ├── feelsbadman.png
│ │ ├── feelsbirthdayman.png
│ │ ├── feelsgoodman.png
│ │ ├── feelssnowman.png
│ │ ├── feelssnowyman.png
│ │ ├── firespeed.png
│ │ ├── fishmoley.png
│ │ ├── foreveralone.png
│ │ ├── gaben.png
│ │ ├── hahaa.png
│ │ ├── hailhelix.png
│ │ ├── hhhehehe.png
│ │ ├── icecold.png
│ │ ├── kappacool.png
│ │ ├── karappa.png
│ │ ├── kkona.png
│ │ ├── lul.png
│ │ ├── m&mjc.png
│ │ ├── monkas.png
│ │ ├── nam.png
│ │ ├── notsquishy.png
│ │ ├── poledoge.png
│ │ ├── rarepepe.png
│ │ ├── ronsmug.png
│ │ ├── saltycorn.png
│ │ ├── shoopdawhoop.png
│ │ ├── sosgame.png
│ │ ├── sqshy.png
│ │ ├── taxibro.png
│ │ ├── tehpolecat.png
│ │ ├── twat.png
│ │ ├── vapenation.png
│ │ ├── vislaud.png
│ │ ├── watchusay.png
│ │ ├── wowee.png
│ │ └── wubtf.png
│ └── gifs
│ │ ├── aaugh.gif
│ │ ├── ayayajam.gif
│ │ ├── balddab.gif
│ │ ├── baldflick.gif
│ │ ├── baldfloss.gif
│ │ ├── baldspin.gif
│ │ ├── baldyappp.gif
│ │ ├── baldyikes.gif
│ │ ├── baners.gif
│ │ ├── bropls.gif
│ │ ├── catjam.gif
│ │ ├── checkers.gif
│ │ ├── click.gif
│ │ ├── coomtime.gif
│ │ ├── crawlers.gif
│ │ ├── deadlole.gif
│ │ ├── deskchan.gif
│ │ ├── eato.gif
│ │ ├── eddiebaldmansmash.gif
│ │ ├── eddieknead.gif
│ │ ├── eddiespin.gif
│ │ ├── eekum.gif
│ │ ├── flappers.gif
│ │ ├── fubaldi.gif
│ │ ├── gamba.gif
│ │ ├── gawkgawk.gif
│ │ ├── guitartime.gif
│ │ ├── humpers.gif
│ │ ├── hypernodders.gif
│ │ ├── hypernopers.gif
│ │ ├── hyperpeepod.gif
│ │ ├── johnsouls.gif
│ │ ├── kissabrother.gif
│ │ ├── kissapregomie.gif
│ │ ├── komodochomp.gif
│ │ ├── lgiggle.gif
│ │ ├── mariorun.gif
│ │ ├── moon2bass.gif
│ │ ├── noted.gif
│ │ ├── peepeegachat.gif
│ │ ├── peepees.gif
│ │ ├── peepersd.gif
│ │ ├── peepoboom.gif
│ │ ├── peepocheering.gif
│ │ ├── peepogolfclap.gif
│ │ ├── peeponarusprint.gif
│ │ ├── peeposhy.gif
│ │ ├── peeposteer.gif
│ │ ├── pepelepsy.gif
│ │ ├── pepemetal.gif
│ │ ├── petthebaldie.gif
│ │ ├── pettheeddie.gif
│ │ ├── pettheqynoa.gif
│ │ ├── pukers.gif
│ │ ├── qynoalurks.gif
│ │ ├── raremoon.gif
│ │ ├── refracting.gif
│ │ ├── robpls.gif
│ │ ├── shruggers.gif
│ │ ├── shushers.gif
│ │ ├── slap.gif
│ │ ├── sneakers.gif
│ │ ├── solarflare.gif
│ │ ├── soulshroom.gif
│ │ ├── speeders.gif
│ │ ├── tanties.gif
│ │ ├── teatime.gif
│ │ ├── teatime2.gif
│ │ ├── tinyteeth.gif
│ │ ├── twerkers.gif
│ │ ├── vanish.gif
│ │ ├── vibers.gif
│ │ ├── wowers.gif
│ │ └── yappp.gif
│ ├── kotlin
│ └── io
│ │ └── getstream
│ │ └── chat
│ │ └── android
│ │ └── twitchclone
│ │ └── designsystem
│ │ ├── Themes.kt
│ │ ├── TwitchLoadingIndicator.kt
│ │ └── assets
│ │ ├── AssetUtils.kt
│ │ └── AssetsProvider.kt
│ └── res
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable
│ ├── ic_emoji.xml
│ ├── ic_gear.xml
│ ├── ic_half_moon.xml
│ ├── ic_heart.xml
│ ├── ic_info.xml
│ ├── ic_launcher_background.xml
│ ├── ic_sun.xml
│ ├── ic_vertical_dots.xml
│ └── reward_ic.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-mdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-xhdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── values-night
│ └── themes.xml
│ └── values
│ ├── colors.xml
│ ├── strings.xml
│ └── themes.xml
├── core-model
├── .gitignore
├── build.gradle.kts
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── kotlin
│ └── io
│ └── getstream
│ └── chat
│ └── android
│ └── twitchclone
│ └── model
│ ├── ChannelExtensions.kt
│ └── Reward.kt
├── core-navigation
├── .gitignore
├── build.gradle.kts
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── kotlin
│ └── io
│ └── getstream
│ └── chat
│ └── android
│ └── twitchclone
│ └── navigation
│ ├── LocalNavigation.kt
│ ├── NavigationCommand.kt
│ ├── Navigator.kt
│ ├── TwitchCloneComposeNavigator.kt
│ └── TwitchScreens.kt
├── core-network
├── .gitignore
├── build.gradle.kts
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── kotlin
│ └── io
│ └── getstream
│ └── chat
│ └── android
│ └── twitchclone
│ └── network
│ ├── TwitchDispatchers.kt
│ ├── di
│ ├── DispatchersModule.kt
│ └── NetworkModule.kt
│ └── service
│ └── RewardsService.kt
├── feature-channels
├── .gitignore
├── build.gradle.kts
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── kotlin
│ └── io
│ └── getstream
│ └── chat
│ └── android
│ └── twitchclone
│ └── channels
│ ├── ChannelInformation.kt
│ ├── StreamerInformation.kt
│ ├── TwitchChannelItem.kt
│ ├── TwitchChannels.kt
│ └── grids
│ ├── GridChannelList.kt
│ └── GridChannels.kt
├── feature-livestream
├── .gitignore
├── build.gradle.kts
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── kotlin
│ └── io
│ └── getstream
│ └── chat
│ └── android
│ └── twitchclone
│ └── livestream
│ ├── EnsurePermissions.kt
│ ├── LivestreamStreamer.kt
│ ├── LivestreamViewModel.kt
│ ├── LivestreamWatcher.kt
│ └── StreamerInformation.kt
├── feature-messages
├── .gitignore
├── build.gradle.kts
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── kotlin
│ └── io
│ └── getstream
│ └── chat
│ └── android
│ └── twitchclone
│ └── messages
│ ├── extensions
│ ├── MessageExtensions.kt
│ └── UserExtensions.kt
│ └── ui
│ ├── emotes
│ └── EmotesContent.kt
│ ├── messages
│ ├── ChannelDescription.kt
│ ├── ChatSettingsIcon.kt
│ ├── SendButton.kt
│ ├── TwitchBottomBar.kt
│ ├── TwitchMessageItem.kt
│ ├── TwitchMessages.kt
│ └── TwitchMessagesViewModel.kt
│ ├── player
│ ├── TwitchVideoPlayer.kt
│ └── VideoPlayer.kt
│ └── rewards
│ ├── RewardExtension.kt
│ ├── RewardIntegration.kt
│ ├── RewardItem.kt
│ └── RewardsContent.kt
├── figures
├── figure0.png
├── figure1.png
├── figure2.png
├── figure3.png
├── figure4.png
├── stream0.png
├── stream1.png
├── stream2.png
├── stream3.png
├── stream4.png
├── stream5.png
└── stream6.png
├── gradle.properties
├── gradle
├── libs.versions.toml
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── previews
├── preview0.png
├── preview1.png
├── preview2.png
├── preview3.png
├── preview4.png
└── preview5.png
├── secrets.defaults.properties
├── secrets.properties
├── settings.gradle.kts
└── spotless
├── copyright.kt
├── copyright.kts
├── copyright.xml
└── spotless.gradle
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 | [*]
3 | # Most of the standard properties are supported
4 | charset = utf-8
5 | end_of_line = lf
6 | indent_size = 2
7 | indent_style = space
8 | max_line_length = 100
9 | insert_final_newline = true
10 | trim_trailing_whitespace = true
11 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # Lines starting with '#' are comments.
2 | # Each line is a file pattern followed by one or more owners.
3 |
4 | # More details are here: https://help.github.com/articles/about-codeowners/
5 |
6 | # The '*' pattern is global owners.
7 | # Not adding in this PR, but I'd like to try adding a global owner set with the entire team.
8 | # One interpretation of their docs is that global owners are added only if not removed
9 | # by a more local rule.
10 |
11 | # Order is important. The last matching pattern has the most precedence.
12 | # The folders are ordered as follows:
13 |
14 | # In each subsection folders are ordered first by depth, then alphabetically.
15 | # This should make it easy to add new rules without breaking existing ones.
16 | * @skydoves
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "gradle" # See documentation for possible values
9 | directory: "/" # Location of package manifests
10 | schedule:
11 | interval: "daily"
12 | # Allow up to 10 open pull requests for pip dependencies
13 | open-pull-requests-limit: 10
14 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | ### 🎯 Goal
2 | Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request. If it fixes a bug or resolves a feature request, be sure to link to that issue.
3 |
4 | ### 🛠 Implementation details
5 | Describe the implementation details for this Pull Request.
6 |
7 | ### ✍️ Explain examples
8 | Explain examples with code for this updates.
9 |
10 | ### Preparing a pull request for review
11 | Ensure your change is properly formatted by running:
12 |
13 | ```gradle
14 | $ ./gradlew spotlessApply
15 | ```
16 |
17 | Please correct any failures before requesting a review.
--------------------------------------------------------------------------------
/.github/workflows/android.yml:
--------------------------------------------------------------------------------
1 | name: Android CI
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | branches: [ main ]
8 |
9 | jobs:
10 | build:
11 | runs-on: macos-latest
12 | steps:
13 | - uses: actions/checkout@v2
14 |
15 | - name: set up JDK
16 | uses: actions/setup-java@v1
17 | with:
18 | distribution: adopt
19 | java-version: 17
20 |
21 | - name: Cache Gradle and wrapper
22 | uses: actions/cache@v2
23 | with:
24 | path: |
25 | ~/.gradle/caches
26 | ~/.gradle/wrapper
27 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
28 | restore-keys: |
29 | ${{ runner.os }}-gradle-
30 |
31 | - name: Make Gradle executable
32 | run: chmod +x ./gradlew
33 |
34 | - name: Build with Gradle
35 | run: |
36 | ./gradlew --scan --stacktrace \
37 | assembleDebug -x :baselineprofile:pixel6api31Setup -x :baselineprofile:pixel6api31NonMinifiedReleaseAndroidTest -x :baselineprofile:collectNonMinifiedReleaseBaselineProfile
38 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the ART/Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 | out/
15 |
16 | # Gradle files
17 | /.idea
18 | !.idea/codeInsightSettings.xml
19 | .gradle/
20 | build/
21 |
22 | # Local configuration file (sdk path, etc)
23 | local.properties
24 |
25 | # Proguard folder generated by Eclipse
26 | proguard/
27 |
28 | # Log Files
29 | *.log
30 |
31 | # Android Studio Navigation editor temp files
32 | .navigation/
33 |
34 | # Android Studio captures folder
35 | captures/
36 |
37 | # Intellij
38 | *.iml
39 | .idea/workspace.xml
40 | .idea/tasks.xml
41 | .idea/gradle.xml
42 | .idea/dictionaries
43 | .idea/libraries
44 | app/.idea/
45 |
46 | # Mac
47 | *.DS_Store
48 |
49 | # Keystore files
50 | *.jks
51 |
52 | # External native build folder generated in Android Studio 2.2 and later
53 | .externalNativeBuild
54 |
55 | # Google Services (e.g. APIs or Firebase)
56 | google-services.json
57 |
58 | # Freeline
59 | freeline.py
60 | freeline/
61 | freeline_project_description.json
62 |
63 | # Eclipse
64 | .project
65 | .settings
66 | .classpath
67 |
68 | # Kotlin
69 | .kotlin
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## How to contribute
2 | We'd love to accept your patches and contributions to this project. There are just a few small guidelines you need to follow.
3 |
4 | ## Preparing a pull request for review
5 | Ensure your change is properly formatted by running:
6 |
7 | ```gradle
8 | ./gradlew spotlessApply
9 | ```
10 |
11 | Please correct any failures before requesting a review.
12 |
13 | ## Code reviews
14 | All submissions, including submissions by project members, require review. We use GitHub pull requests for this purpose. Consult [GitHub Help](https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests) for more information on using pull requests.
15 |
--------------------------------------------------------------------------------
/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: skydoves
2 | custom: ["https://www.paypal.me/skydoves", "https://www.buymeacoffee.com/skydoves"]
3 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/benchmark-rules.pro:
--------------------------------------------------------------------------------
1 | -dontobfuscate
2 | -dontwarn com.google.errorprone.annotations.InlineMe
3 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.kts.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
20 |
21 |
22 |
23 |
31 |
32 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
48 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/io/getstream/chat/android/twitchclone/MainActivity.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone
18 |
19 | import android.os.Bundle
20 | import androidx.activity.ComponentActivity
21 | import androidx.activity.compose.setContent
22 | import dagger.hilt.android.AndroidEntryPoint
23 | import io.getstream.chat.android.client.ChatClient
24 | import io.getstream.chat.android.twitchclone.ui.TwitchCloneMain
25 |
26 | @AndroidEntryPoint
27 | class MainActivity : ComponentActivity() {
28 |
29 | override fun onCreate(savedInstanceState: Bundle?) {
30 | super.onCreate(savedInstanceState)
31 |
32 | setContent { TwitchCloneMain() }
33 | }
34 |
35 | override fun onDestroy() {
36 | super.onDestroy()
37 |
38 | ChatClient.instance().disconnect(false).enqueue()
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/io/getstream/chat/android/twitchclone/TwitchCloneApp.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone
18 |
19 | import android.app.Application
20 | import dagger.hilt.android.HiltAndroidApp
21 |
22 | @HiltAndroidApp
23 | class TwitchCloneApp : Application()
24 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/io/getstream/chat/android/twitchclone/initializer/AssetsInitializer.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.initializer
18 |
19 | import android.content.Context
20 | import androidx.startup.Initializer
21 | import io.getstream.chat.android.twitchclone.designsystem.assets.AssetsProvider
22 | import io.getstream.log.streamLog
23 |
24 | class AssetsInitializer : Initializer {
25 |
26 | override fun create(context: Context) {
27 | streamLog { "AssetsInitializer is initialized" }
28 |
29 | AssetsProvider.loadBadges(context)
30 | AssetsProvider.loadReactions(context)
31 | }
32 |
33 | override fun dependencies(): List>> = emptyList()
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/io/getstream/chat/android/twitchclone/initializer/MainInitializer.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.initializer
18 |
19 | import android.content.Context
20 | import androidx.startup.Initializer
21 |
22 | class MainInitializer : Initializer {
23 |
24 | override fun create(context: Context) = Unit
25 |
26 | override fun dependencies(): List>> = listOf(
27 | StreamLogInitializer::class.java,
28 | StreamChatInitializer::class.java,
29 | StreamVideoInitializer::class.java,
30 | AssetsInitializer::class.java
31 | )
32 | }
33 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/io/getstream/chat/android/twitchclone/initializer/StreamChatInitializer.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.initializer
18 |
19 | import android.content.Context
20 | import androidx.startup.Initializer
21 | import io.getstream.chat.android.client.ChatClient
22 | import io.getstream.chat.android.client.logger.ChatLogLevel
23 | import io.getstream.chat.android.models.User
24 | import io.getstream.chat.android.offline.plugin.factory.StreamOfflinePluginFactory
25 | import io.getstream.chat.android.state.plugin.config.StatePluginConfig
26 | import io.getstream.chat.android.state.plugin.factory.StreamStatePluginFactory
27 | import io.getstream.chat.android.twitchclone.BuildConfig
28 | import io.getstream.log.streamLog
29 |
30 | /**
31 | * StreamChatInitializer initializes all Stream Client components.
32 | */
33 | class StreamChatInitializer : Initializer {
34 |
35 | override fun create(context: Context) {
36 | streamLog { "StreamChatInitializer is initialized" }
37 |
38 | /**
39 | * initialize a global instance of the [ChatClient].
40 | * The ChatClient is the main entry point for all low-level operations on chat.
41 | * e.g, connect/disconnect user to the server, send/update/pin message, etc.
42 | */
43 | val logLevel = if (BuildConfig.DEBUG) ChatLogLevel.ALL else ChatLogLevel.NOTHING
44 | val offlinePluginFactory = StreamOfflinePluginFactory(
45 | appContext = context
46 | )
47 | val statePluginFactory = StreamStatePluginFactory(
48 | config = StatePluginConfig(
49 | backgroundSyncEnabled = true,
50 | userPresence = true
51 | ),
52 | appContext = context
53 | )
54 | val chatClient = ChatClient.Builder(BuildConfig.STREAM_API_KEY, context)
55 | .withPlugins(offlinePluginFactory, statePluginFactory)
56 | .logLevel(logLevel)
57 | .build()
58 |
59 | val user = User(
60 | id = "jaewoong12",
61 | name = "Jaewoong"
62 | )
63 |
64 | val token = chatClient.devToken(user.id)
65 | chatClient.connectUser(user, token).enqueue()
66 | }
67 |
68 | override fun dependencies(): List>> =
69 | listOf(StreamLogInitializer::class.java)
70 | }
71 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/io/getstream/chat/android/twitchclone/initializer/StreamLogInitializer.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.initializer
18 |
19 | import android.content.Context
20 | import androidx.startup.Initializer
21 | import io.getstream.log.Priority
22 | import io.getstream.log.android.AndroidStreamLogger
23 | import io.getstream.log.android.BuildConfig
24 | import io.getstream.log.streamLog
25 |
26 | class StreamLogInitializer : Initializer {
27 |
28 | override fun create(context: Context) {
29 | if (BuildConfig.DEBUG) {
30 | AndroidStreamLogger.install(minPriority = Priority.DEBUG)
31 | streamLog { "StreamLogInitializer is initialized" }
32 | }
33 | }
34 |
35 | override fun dependencies(): List>> = emptyList()
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/io/getstream/chat/android/twitchclone/initializer/StreamVideoInitializer.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.initializer
18 |
19 | import android.content.Context
20 | import androidx.startup.Initializer
21 | import io.getstream.chat.android.twitchclone.BuildConfig
22 | import io.getstream.log.streamLog
23 | import io.getstream.video.android.core.StreamVideo
24 | import io.getstream.video.android.core.StreamVideoBuilder
25 | import io.getstream.video.android.core.notifications.NotificationConfig
26 | import io.getstream.video.android.model.User
27 |
28 | class StreamVideoInitializer : Initializer {
29 |
30 | override fun create(context: Context) {
31 | streamLog { "StreamVideoInitializer is initialized" }
32 |
33 | val userId = "jaewoong"
34 | StreamVideoBuilder(
35 | context = context,
36 | apiKey = BuildConfig.STREAM_API_KEY,
37 | notificationConfig = NotificationConfig(hideRingingNotificationInForeground = true),
38 | runForegroundServiceForCalls = false,
39 | token = StreamVideo.devToken(userId),
40 | user = User(
41 | id = userId,
42 | name = "Jaewoong",
43 | image = "http://placekitten.com/200/300",
44 | role = "admin"
45 | )
46 | ).build()
47 | }
48 |
49 | override fun dependencies(): List>> =
50 | listOf(StreamLogInitializer::class.java)
51 | }
52 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/io/getstream/chat/android/twitchclone/navigation/NavSlideComposable.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.navigation
18 |
19 | import androidx.compose.animation.AnimatedContentScope
20 | import androidx.compose.animation.AnimatedContentTransitionScope
21 | import androidx.compose.animation.core.tween
22 | import androidx.compose.runtime.Composable
23 | import androidx.navigation.NamedNavArgument
24 | import androidx.navigation.NavBackStackEntry
25 | import androidx.navigation.NavDeepLink
26 | import androidx.navigation.NavGraphBuilder
27 | import androidx.navigation.compose.composable
28 |
29 | fun NavGraphBuilder.slideComposable(
30 | route: String,
31 | arguments: List = emptyList(),
32 | deepLinks: List = emptyList(),
33 | content: @Composable AnimatedContentScope.(NavBackStackEntry) -> Unit
34 | ) {
35 | composable(
36 | route = route,
37 | enterTransition = {
38 | slideIntoContainer(
39 | towards = AnimatedContentTransitionScope.SlideDirection.Companion.Left,
40 | animationSpec = tween(500)
41 | )
42 | },
43 | exitTransition = {
44 | slideOutOfContainer(
45 | towards = AnimatedContentTransitionScope.SlideDirection.Companion.Left,
46 | animationSpec = tween(500)
47 | )
48 | },
49 | popEnterTransition = {
50 | slideIntoContainer(
51 | towards = AnimatedContentTransitionScope.SlideDirection.Companion.Right,
52 | animationSpec = tween(500)
53 | )
54 | },
55 | popExitTransition = {
56 | slideOutOfContainer(
57 | towards = AnimatedContentTransitionScope.SlideDirection.Companion.Right,
58 | animationSpec = tween(500)
59 | )
60 | },
61 | arguments = arguments,
62 | deepLinks = deepLinks,
63 | content = content
64 | )
65 | }
66 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/io/getstream/chat/android/twitchclone/navigation/TwitchNavHost.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.navigation
18 |
19 | import androidx.compose.runtime.Composable
20 | import androidx.navigation.NavHostController
21 | import androidx.navigation.compose.NavHost
22 |
23 | @Composable
24 | fun TwitchNavHost(
25 | navHostController: NavHostController
26 | ) {
27 | NavHost(
28 | navController = navHostController,
29 | startDestination = TwitchScreens.Channels.route
30 | ) {
31 | twitchAppHomeNavigation()
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/io/getstream/chat/android/twitchclone/ui/TwitchCloneMain.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.ui
18 |
19 | import android.os.Build
20 | import androidx.compose.runtime.Composable
21 | import androidx.compose.runtime.CompositionLocalProvider
22 | import androidx.compose.runtime.LaunchedEffect
23 | import androidx.compose.runtime.remember
24 | import androidx.compose.ui.platform.LocalContext
25 | import androidx.navigation.compose.rememberNavController
26 | import coil.ImageLoader
27 | import coil.decode.GifDecoder
28 | import coil.decode.ImageDecoderDecoder
29 | import com.skydoves.landscapist.coil.LocalCoilImageLoader
30 | import io.getstream.chat.android.twitchclone.designsystem.TwitchTheme
31 | import io.getstream.chat.android.twitchclone.navigation.LocalComposeNavigator
32 | import io.getstream.chat.android.twitchclone.navigation.TwitchCloneComposeNavigator
33 | import io.getstream.chat.android.twitchclone.navigation.TwitchNavHost
34 |
35 | @Composable
36 | fun TwitchCloneMain() {
37 | val context = LocalContext.current
38 | val imageLoader = remember {
39 | ImageLoader.Builder(context)
40 | .components {
41 | if (Build.VERSION.SDK_INT >= 28) {
42 | add(ImageDecoderDecoder.Factory())
43 | } else {
44 | add(GifDecoder.Factory())
45 | }
46 | }
47 | .build()
48 | }
49 | val appComposeNavigator = remember { TwitchCloneComposeNavigator() }
50 |
51 | CompositionLocalProvider(
52 | LocalCoilImageLoader provides imageLoader,
53 | LocalComposeNavigator provides appComposeNavigator
54 | ) {
55 | TwitchTheme {
56 | val navHostController = rememberNavController()
57 |
58 | LaunchedEffect(Unit) {
59 | appComposeNavigator.handleNavigationCommands(navHostController)
60 | }
61 |
62 | TwitchNavHost(
63 | navHostController = navHostController
64 | )
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/baselineprofile/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/baselineprofile/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import io.getstream.chat.android.Configuration
2 |
3 | @Suppress("DSL_SCOPE_VIOLATION")
4 | plugins {
5 | id(libs.plugins.android.test.get().pluginId)
6 | id(libs.plugins.kotlin.android.get().pluginId)
7 | id(libs.plugins.baseline.profile.get().pluginId)
8 | }
9 |
10 | android {
11 | namespace = "io.getstream.chat.android.twitchclone.baselineprofile"
12 | compileSdk = Configuration.compileSdk
13 |
14 | compileOptions {
15 | sourceCompatibility = JavaVersion.VERSION_17
16 | targetCompatibility = JavaVersion.VERSION_17
17 | }
18 |
19 | kotlinOptions {
20 | jvmTarget = libs.versions.jvmTarget.get()
21 | }
22 |
23 | defaultConfig {
24 | minSdk = 24
25 | targetSdk = Configuration.targetSdk
26 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
27 | }
28 |
29 | buildTypes {
30 | create("benchmark") {
31 | isDebuggable = false
32 | signingConfig = signingConfigs.getByName("debug")
33 | matchingFallbacks += listOf("release")
34 | }
35 | }
36 |
37 | targetProjectPath = ":app"
38 |
39 | testOptions.managedDevices.devices {
40 | maybeCreate("pixel6api31").apply {
41 | device = "Pixel 6"
42 | apiLevel = 31
43 | systemImageSource = "aosp"
44 | }
45 | }
46 | }
47 |
48 | // This is the plugin configuration. Everything is optional. Defaults are in the
49 | // comments. In this example, you use the GMD added earlier and disable connected devices.
50 | baselineProfile {
51 |
52 | // This specifies the managed devices to use that you run the tests on. The default
53 | // is none.
54 | managedDevices += "pixel6api31"
55 |
56 | // This enables using connected devices to generate profiles. The default is true.
57 | // When using connected devices, they must be rooted or API 33 and higher.
58 | useConnectedDevices = false
59 | }
60 |
61 | dependencies {
62 | implementation(libs.androidx.test.runner)
63 | implementation(libs.androidx.test.uiautomator)
64 | implementation(libs.androidx.benchmark.macro)
65 | implementation(libs.androidx.profileinstaller)
66 | }
67 |
--------------------------------------------------------------------------------
/baselineprofile/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/baselineprofile/src/main/kotlin/io/getstream/chat/android/twitchclone/baselineprofile/BaselineProfileGenerator.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Designed and developed by 2023 skydoves (Jaewoong Eum)
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.getstream.chat.android.twitchclone.baselineprofile
17 |
18 | import android.os.Build
19 | import androidx.annotation.RequiresApi
20 | import androidx.benchmark.macro.junit4.BaselineProfileRule
21 | import org.junit.Rule
22 | import org.junit.Test
23 |
24 | @RequiresApi(Build.VERSION_CODES.P)
25 | class BaselineProfileGenerator {
26 | @get:Rule
27 | val baselineProfileRule = BaselineProfileRule()
28 |
29 | @Test
30 | fun startup() =
31 | baselineProfileRule.collect(
32 | packageName = "io.getstream.chat.android.twitchclone",
33 | includeInStartupProfile = true,
34 | stableIterations = 2,
35 | maxIterations = 8,
36 | ) {
37 | pressHome()
38 | // This block defines the app's critical user journey. Here we are interested in
39 | // optimizing for app startup. But you can also navigate and scroll
40 | // through your most important UI.
41 | startActivityAndWait()
42 | device.waitForIdle()
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/build-logic/convention/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `kotlin-dsl`
3 | }
4 |
5 | group = "io.getstream.chat.android.twitchclone.buildlogic"
6 |
7 | java {
8 | sourceCompatibility = JavaVersion.VERSION_17
9 | targetCompatibility = JavaVersion.VERSION_17
10 | }
11 |
12 | dependencies {
13 | compileOnly(libs.android.gradlePlugin)
14 | compileOnly(libs.kotlin.gradlePlugin)
15 | compileOnly(libs.compose.compiler.gradlePlugin)
16 | compileOnly(libs.spotless.gradlePlugin)
17 | }
18 |
19 | gradlePlugin {
20 | plugins {
21 | register("androidApplicationCompose") {
22 | id = "getstream.android.application.compose"
23 | implementationClass = "AndroidApplicationComposeConventionPlugin"
24 | }
25 | register("androidApplication") {
26 | id = "getstream.android.application"
27 | implementationClass = "AndroidApplicationConventionPlugin"
28 | }
29 | register("androidLibraryCompose") {
30 | id = "getstream.android.library.compose"
31 | implementationClass = "AndroidLibraryComposeConventionPlugin"
32 | }
33 | register("androidLibrary") {
34 | id = "getstream.android.library"
35 | implementationClass = "AndroidLibraryConventionPlugin"
36 | }
37 | register("androidFeature") {
38 | id = "getstream.android.feature"
39 | implementationClass = "AndroidFeatureConventionPlugin"
40 | }
41 | register("androidHilt") {
42 | id = "getstream.android.hilt"
43 | implementationClass = "AndroidHiltConventionPlugin"
44 | }
45 | register("spotless") {
46 | id = "getstream.spotless"
47 | implementationClass = "SpotlessConventionPlugin"
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/AndroidApplicationComposeConventionPlugin.kt:
--------------------------------------------------------------------------------
1 | import com.android.build.gradle.internal.dsl.BaseAppModuleExtension
2 | import io.getstream.chat.android.twitchclone.configureAndroidCompose
3 | import org.gradle.api.Plugin
4 | import org.gradle.api.Project
5 | import org.gradle.kotlin.dsl.getByType
6 |
7 | class AndroidApplicationComposeConventionPlugin : Plugin {
8 | override fun apply(target: Project) {
9 | with(target) {
10 | pluginManager.apply("com.android.application")
11 | val extension = extensions.getByType()
12 | configureAndroidCompose(extension)
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt:
--------------------------------------------------------------------------------
1 | import com.android.build.gradle.internal.dsl.BaseAppModuleExtension
2 | import io.getstream.chat.android.twitchclone.configureKotlinAndroid
3 | import org.gradle.api.Plugin
4 | import org.gradle.api.Project
5 | import org.gradle.kotlin.dsl.configure
6 |
7 | class AndroidApplicationConventionPlugin : Plugin {
8 | override fun apply(target: Project) {
9 | with(target) {
10 | with(pluginManager) {
11 | apply("com.android.application")
12 | apply("org.jetbrains.kotlin.android")
13 | }
14 |
15 | extensions.configure {
16 | configureKotlinAndroid(this)
17 | defaultConfig.targetSdk = 34
18 | }
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt:
--------------------------------------------------------------------------------
1 | import org.gradle.api.Plugin
2 | import org.gradle.api.Project
3 | import org.gradle.api.artifacts.VersionCatalogsExtension
4 | import org.gradle.kotlin.dsl.dependencies
5 | import org.gradle.kotlin.dsl.getByType
6 |
7 | class AndroidFeatureConventionPlugin : Plugin {
8 | override fun apply(target: Project) {
9 | with(target) {
10 | pluginManager.apply {
11 | apply("com.android.library")
12 | apply("org.jetbrains.kotlin.android")
13 | }
14 |
15 | val libs = extensions.getByType().named("libs")
16 |
17 | dependencies {
18 | add("implementation", project(":core-designsystem"))
19 | add("implementation", project(":core-navigation"))
20 | add("implementation", project(":core-data"))
21 |
22 | add("implementation", libs.findLibrary("kotlinx.coroutines.android").get())
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/AndroidHiltConventionPlugin.kt:
--------------------------------------------------------------------------------
1 | import org.gradle.api.Plugin
2 | import org.gradle.api.Project
3 | import org.gradle.api.artifacts.VersionCatalogsExtension
4 | import org.gradle.kotlin.dsl.dependencies
5 | import org.gradle.kotlin.dsl.getByType
6 |
7 | class AndroidHiltConventionPlugin : Plugin {
8 | override fun apply(target: Project) {
9 | with(target) {
10 | with(pluginManager) {
11 | apply("dagger.hilt.android.plugin")
12 | apply("com.google.devtools.ksp")
13 | }
14 |
15 | val libs = extensions.getByType().named("libs")
16 |
17 | dependencies {
18 | add("implementation", libs.findLibrary("hilt.android").get())
19 | add("implementation", libs.findLibrary("androidx.hilt.navigation.compose").get())
20 | add("ksp", libs.findLibrary("hilt.compiler").get())
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt:
--------------------------------------------------------------------------------
1 | import com.android.build.gradle.LibraryExtension
2 | import io.getstream.chat.android.twitchclone.configureAndroidCompose
3 | import org.gradle.api.Plugin
4 | import org.gradle.api.Project
5 | import org.gradle.kotlin.dsl.getByType
6 |
7 | class AndroidLibraryComposeConventionPlugin : Plugin {
8 | override fun apply(target: Project) {
9 | with(target) {
10 | pluginManager.apply("com.android.library")
11 | val extension = extensions.getByType()
12 | configureAndroidCompose(extension)
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt:
--------------------------------------------------------------------------------
1 | import com.android.build.gradle.LibraryExtension
2 | import io.getstream.chat.android.twitchclone.configureKotlinAndroid
3 | import org.gradle.api.Plugin
4 | import org.gradle.api.Project
5 | import org.gradle.kotlin.dsl.configure
6 |
7 | class AndroidLibraryConventionPlugin : Plugin {
8 | override fun apply(target: Project) {
9 | with(target) {
10 | with(pluginManager) {
11 | apply("com.android.library")
12 | apply("org.jetbrains.kotlin.android")
13 | }
14 |
15 | extensions.configure {
16 | configureKotlinAndroid(this)
17 | defaultConfig.targetSdk = 34
18 | }
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/SpotlessConventionPlugin.kt:
--------------------------------------------------------------------------------
1 | import com.diffplug.gradle.spotless.SpotlessExtension
2 | import org.gradle.api.Plugin
3 | import org.gradle.api.Project
4 | import org.gradle.kotlin.dsl.configure
5 |
6 | class SpotlessConventionPlugin : Plugin {
7 | override fun apply(target: Project) {
8 | with(target) {
9 | pluginManager.apply("com.diffplug.spotless")
10 |
11 | extensions.configure {
12 | kotlin {
13 | target("**/*.kt")
14 | targetExclude("**/build/**/*.kt")
15 | ktlint()
16 | .setUseExperimental(true)
17 | .userData(mapOf("android" to "true"))
18 | .editorConfigOverride(mapOf("indent_size" to 2, "continuation_indent_size" to 2))
19 | licenseHeaderFile(rootProject.file("$rootDir/spotless/copyright.kt"))
20 | }
21 | format("kts") {
22 | target("**/*.kts")
23 | targetExclude("**/build/**/*.kts")
24 | // Look for the first line that doesn't have a block comment (assumed to be the license)
25 | licenseHeaderFile(rootProject.file("spotless/copyright.kts"), "(^(?![\\/ ]\\*).*$)")
26 | }
27 | format("xml") {
28 | target("**/*.xml")
29 | targetExclude("**/build/**/*.xml")
30 | // Look for the first XML tag that isn't a comment (
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/core-data/src/main/kotlin/io/getstream/chat/android/twitchclone/data/coroutines/WhileSubscribedOrRetained.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.data.coroutines
18 |
19 | import android.os.Handler
20 | import android.os.Looper
21 | import android.view.Choreographer
22 | import kotlinx.coroutines.CompletableDeferred
23 | import kotlinx.coroutines.flow.Flow
24 | import kotlinx.coroutines.flow.SharingCommand
25 | import kotlinx.coroutines.flow.SharingStarted
26 | import kotlinx.coroutines.flow.StateFlow
27 | import kotlinx.coroutines.flow.distinctUntilChanged
28 | import kotlinx.coroutines.flow.dropWhile
29 | import kotlinx.coroutines.flow.transformLatest
30 |
31 | /**
32 | * Sharing is started when the first subscriber appears,
33 | * immediately stops when the last subscriber disappears (by default),
34 | * keeping the replay cache forever (by default) even if configuration changes happen.
35 | *
36 | * https://py.hashnode.dev/whilesubscribed5000
37 | */
38 | data object WhileSubscribedOrRetained : SharingStarted {
39 |
40 | private val handler = Handler(Looper.getMainLooper())
41 |
42 | override fun command(subscriptionCount: StateFlow): Flow = subscriptionCount
43 | .transformLatest { count ->
44 | if (count > 0) {
45 | emit(SharingCommand.START)
46 | } else {
47 | val posted = CompletableDeferred()
48 | // This code is perfect. Do not change a thing.
49 | Choreographer.getInstance().postFrameCallback {
50 | handler.postAtFrontOfQueue {
51 | handler.post {
52 | posted.complete(Unit)
53 | }
54 | }
55 | }
56 | posted.await()
57 | emit(SharingCommand.STOP)
58 | }
59 | }
60 | .dropWhile { it != SharingCommand.START }
61 | .distinctUntilChanged()
62 |
63 | override fun toString(): String = "WhileSubscribedOrRetained"
64 | }
65 |
--------------------------------------------------------------------------------
/core-data/src/main/kotlin/io/getstream/chat/android/twitchclone/data/di/DataModule.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.data.di
18 |
19 | import dagger.Binds
20 | import dagger.Module
21 | import dagger.hilt.InstallIn
22 | import dagger.hilt.components.SingletonComponent
23 | import io.getstream.chat.android.twitchclone.data.repository.RewardRepository
24 | import io.getstream.chat.android.twitchclone.data.repository.RewardRepositoryImpl
25 |
26 | @Module
27 | @InstallIn(SingletonComponent::class)
28 | internal interface DataModule {
29 |
30 | @Binds
31 | fun bindsCallHistoryRepository(
32 | rewardRepositoryImpl: RewardRepositoryImpl
33 | ): RewardRepository
34 | }
35 |
--------------------------------------------------------------------------------
/core-data/src/main/kotlin/io/getstream/chat/android/twitchclone/data/mapper/Mappers.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.data.mapper
18 |
19 | import io.getstream.chat.android.twitchclone.database.entity.RewardEntity
20 | import io.getstream.chat.android.twitchclone.model.Reward
21 |
22 | fun RewardEntity.toModel(): Reward {
23 | return Reward(name, color, icon, tokenAmount)
24 | }
25 |
--------------------------------------------------------------------------------
/core-data/src/main/kotlin/io/getstream/chat/android/twitchclone/data/repository/RewardRepository.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.data.repository
18 |
19 | import com.skydoves.sandwich.ApiResponse
20 | import io.getstream.chat.android.twitchclone.model.Reward
21 | import kotlinx.coroutines.flow.Flow
22 |
23 | interface RewardRepository {
24 |
25 | fun getRewardStream(): Flow>>
26 |
27 | suspend fun updateRewards(rewards: ApiResponse>)
28 | }
29 |
--------------------------------------------------------------------------------
/core-data/src/main/kotlin/io/getstream/chat/android/twitchclone/data/repository/RewardRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.data.repository
18 |
19 | import com.skydoves.sandwich.ApiResponse
20 | import com.skydoves.sandwich.getOrNull
21 | import io.getstream.chat.android.twitchclone.data.mapper.toModel
22 | import io.getstream.chat.android.twitchclone.database.dao.RewardDao
23 | import io.getstream.chat.android.twitchclone.database.entity.asEntity
24 | import io.getstream.chat.android.twitchclone.model.Reward
25 | import io.getstream.chat.android.twitchclone.network.Dispatcher
26 | import io.getstream.chat.android.twitchclone.network.TwitchDispatchers
27 | import io.getstream.chat.android.twitchclone.network.service.RewardsService
28 | import javax.inject.Inject
29 | import kotlinx.coroutines.CoroutineDispatcher
30 | import kotlinx.coroutines.flow.Flow
31 | import kotlinx.coroutines.flow.flow
32 | import kotlinx.coroutines.flow.flowOn
33 |
34 | /**
35 | * This is an implementation of [RewardRepository].
36 | *
37 | * Make sure the implementation class must not be exposed to the outside by using 'internal' visibility modifier.
38 | */
39 | internal class RewardRepositoryImpl @Inject constructor(
40 | @Dispatcher(TwitchDispatchers.IO) private val ioDispatcher: CoroutineDispatcher,
41 | private val rewardsService: RewardsService,
42 | private val rewardDao: RewardDao
43 | ) : RewardRepository {
44 |
45 | override fun getRewardStream(): Flow>> = flow {
46 | val offlineRewards = rewardDao.getRewards()
47 | if (offlineRewards.isEmpty()) {
48 | val apiResponse = rewardsService.fetchRewards()
49 | updateRewards(apiResponse)
50 | emit(apiResponse)
51 | } else {
52 | emit(ApiResponse.Success(offlineRewards.map { it.toModel() }))
53 | }
54 | }.flowOn(ioDispatcher)
55 |
56 | override suspend fun updateRewards(rewards: ApiResponse>) {
57 | val entities = rewards.getOrNull()?.map { it.asEntity() } ?: return
58 | rewardDao.insertRewards(entities)
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/core-database/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/core-database/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | plugins {
17 | id("getstream.android.library")
18 | id("getstream.android.hilt")
19 | id("getstream.spotless")
20 | id("com.google.devtools.ksp")
21 | }
22 |
23 | android {
24 | namespace = "io.getstream.chat.android.twitchclone.database"
25 | defaultConfig {
26 | // The schemas directory contains a schema file for each version of the Room database.
27 | // This is required to enable Room auto migrations.
28 | // See https://developer.android.com/reference/kotlin/androidx/room/AutoMigration.
29 | ksp {
30 | arg("room.schemaLocation", "$projectDir/schemas")
31 | }
32 | }
33 | }
34 |
35 | dependencies {
36 | implementation(project(":core-model"))
37 |
38 | implementation(libs.androidx.room.runtime)
39 | implementation(libs.androidx.room.ktx)
40 | ksp(libs.androidx.room.compiler)
41 | }
42 |
--------------------------------------------------------------------------------
/core-database/schemas/io.getstream.chat.android.twitchclone.database.TwitchDatabase/1.json:
--------------------------------------------------------------------------------
1 | {
2 | "formatVersion": 1,
3 | "database": {
4 | "version": 1,
5 | "identityHash": "c24a63fb1161cd6e8a14736c19dc2aec",
6 | "entities": [
7 | {
8 | "tableName": "reward",
9 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `color` TEXT NOT NULL, `icon` TEXT NOT NULL, `tokenAmount` INTEGER NOT NULL, PRIMARY KEY(`name`))",
10 | "fields": [
11 | {
12 | "fieldPath": "name",
13 | "columnName": "name",
14 | "affinity": "TEXT",
15 | "notNull": true
16 | },
17 | {
18 | "fieldPath": "color",
19 | "columnName": "color",
20 | "affinity": "TEXT",
21 | "notNull": true
22 | },
23 | {
24 | "fieldPath": "icon",
25 | "columnName": "icon",
26 | "affinity": "TEXT",
27 | "notNull": true
28 | },
29 | {
30 | "fieldPath": "tokenAmount",
31 | "columnName": "tokenAmount",
32 | "affinity": "INTEGER",
33 | "notNull": true
34 | }
35 | ],
36 | "primaryKey": {
37 | "autoGenerate": false,
38 | "columnNames": [
39 | "name"
40 | ]
41 | },
42 | "indices": [],
43 | "foreignKeys": []
44 | }
45 | ],
46 | "views": [],
47 | "setupQueries": [
48 | "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
49 | "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'c24a63fb1161cd6e8a14736c19dc2aec')"
50 | ]
51 | }
52 | }
--------------------------------------------------------------------------------
/core-database/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/core-database/src/main/kotlin/io/getstream/chat/android/twitchclone/database/TwitchDatabase.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.database
18 |
19 | import androidx.room.Database
20 | import androidx.room.RoomDatabase
21 | import io.getstream.chat.android.twitchclone.database.dao.RewardDao
22 | import io.getstream.chat.android.twitchclone.database.entity.RewardEntity
23 |
24 | @Database(
25 | entities = [RewardEntity::class],
26 | version = 1,
27 | exportSchema = true
28 | )
29 | internal abstract class TwitchDatabase : RoomDatabase() {
30 | abstract fun rewardDao(): RewardDao
31 | }
32 |
--------------------------------------------------------------------------------
/core-database/src/main/kotlin/io/getstream/chat/android/twitchclone/database/dao/RewardDao.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.database.dao
18 |
19 | import androidx.room.Dao
20 | import androidx.room.Insert
21 | import androidx.room.OnConflictStrategy
22 | import androidx.room.Query
23 | import io.getstream.chat.android.twitchclone.database.entity.RewardEntity
24 |
25 | @Dao
26 | interface RewardDao {
27 |
28 | @Query(value = "SELECT * FROM reward")
29 | suspend fun getRewards(): List
30 |
31 | @Insert(onConflict = OnConflictStrategy.REPLACE)
32 | suspend fun insertRewards(rewardEntity: List)
33 | }
34 |
--------------------------------------------------------------------------------
/core-database/src/main/kotlin/io/getstream/chat/android/twitchclone/database/di/DatabaseModule.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.database.di
18 |
19 | import android.content.Context
20 | import androidx.room.Room
21 | import dagger.Module
22 | import dagger.Provides
23 | import dagger.hilt.InstallIn
24 | import dagger.hilt.android.qualifiers.ApplicationContext
25 | import dagger.hilt.components.SingletonComponent
26 | import io.getstream.chat.android.twitchclone.database.TwitchDatabase
27 | import io.getstream.chat.android.twitchclone.database.dao.RewardDao
28 | import javax.inject.Singleton
29 |
30 | @Module
31 | @InstallIn(SingletonComponent::class)
32 | internal object DatabaseModule {
33 |
34 | @Provides
35 | @Singleton
36 | fun provideTwitchCloneDatabase(
37 | @ApplicationContext context: Context
38 | ): TwitchDatabase = Room.databaseBuilder(
39 | context,
40 | TwitchDatabase::class.java,
41 | "twitchclone-database"
42 | ).build()
43 |
44 | @Provides
45 | @Singleton
46 | fun provideTwitchUserDao(
47 | twitchDatabase: TwitchDatabase
48 | ): RewardDao {
49 | return twitchDatabase.rewardDao()
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/core-database/src/main/kotlin/io/getstream/chat/android/twitchclone/database/entity/RewardEntity.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.database.entity
18 |
19 | import androidx.room.Entity
20 | import androidx.room.PrimaryKey
21 | import io.getstream.chat.android.twitchclone.model.Reward
22 |
23 | @Entity(tableName = "reward")
24 | data class RewardEntity(
25 | @PrimaryKey val name: String,
26 | val color: String,
27 | val icon: String,
28 | val tokenAmount: Int
29 | )
30 |
31 | fun Reward.asEntity(): RewardEntity {
32 | return RewardEntity(
33 | name = name,
34 | color = color,
35 | icon = icon,
36 | tokenAmount = tokenAmount
37 | )
38 | }
39 |
--------------------------------------------------------------------------------
/core-designsystem/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/core-designsystem/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | plugins {
17 | id("getstream.android.library")
18 | id("getstream.android.library.compose")
19 | id("getstream.spotless")
20 | }
21 |
22 | android {
23 | namespace = "io.getstream.chat.android.twitchclone.designsystem"
24 | }
25 |
26 | dependencies {
27 | api(libs.androidx.startup)
28 |
29 | // Stream SDK
30 | implementation(libs.stream.chat.compose)
31 | implementation(libs.stream.video.compose)
32 |
33 | // image loading
34 | api(libs.landscapist.coil)
35 | api(libs.landscapist.animation)
36 | api(libs.landscapist.placeholder)
37 |
38 | // compose
39 | api(libs.androidx.compose.runtime)
40 | api(libs.androidx.compose.ui)
41 | api(libs.androidx.compose.ui.tooling)
42 | api(libs.androidx.compose.ui.tooling.preview)
43 | api(libs.androidx.compose.material.iconsExtended)
44 | api(libs.androidx.compose.material)
45 | api(libs.androidx.compose.foundation)
46 | api(libs.androidx.compose.foundation.layout)
47 | api(libs.androidx.compose.constraintlayout)
48 | }
49 |
--------------------------------------------------------------------------------
/core-designsystem/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/badges/cat.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/badges/cat.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/badges/cat2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/badges/cat2.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/badges/cool.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/badges/cool.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/badges/gold.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/badges/gold.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/badges/prime.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/badges/prime.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/badges/star.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/badges/star.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/angelthump.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/angelthump.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/ariw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/ariw.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/brobalt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/brobalt.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/bttvnice.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/bttvnice.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/burself.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/burself.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/candianrage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/candianrage.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/cigrip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/cigrip.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/concerndoge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/concerndoge.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/cruw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/cruw.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/cvhazmat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/cvhazmat.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/cvl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/cvl.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/cvmask.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/cvmask.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/cvr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/cvr.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/datsauce.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/datsauce.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/dogchamp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/dogchamp.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/duckerz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/duckerz.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/feelsamazingman.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/feelsamazingman.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/feelsbadman.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/feelsbadman.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/feelsbirthdayman.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/feelsbirthdayman.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/feelsgoodman.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/feelsgoodman.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/feelssnowman.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/feelssnowman.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/feelssnowyman.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/feelssnowyman.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/firespeed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/firespeed.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/fishmoley.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/fishmoley.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/foreveralone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/foreveralone.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/gaben.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/gaben.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/hahaa.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/hahaa.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/hailhelix.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/hailhelix.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/hhhehehe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/hhhehehe.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/icecold.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/icecold.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/kappacool.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/kappacool.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/karappa.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/karappa.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/kkona.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/kkona.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/lul.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/lul.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/m&mjc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/m&mjc.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/monkas.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/monkas.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/nam.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/nam.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/notsquishy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/notsquishy.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/poledoge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/poledoge.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/rarepepe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/rarepepe.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/ronsmug.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/ronsmug.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/saltycorn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/saltycorn.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/shoopdawhoop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/shoopdawhoop.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/sosgame.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/sosgame.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/sqshy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/sqshy.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/taxibro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/taxibro.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/tehpolecat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/tehpolecat.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/twat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/twat.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/vapenation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/vapenation.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/vislaud.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/vislaud.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/watchusay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/watchusay.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/wowee.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/wowee.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/emotes/wubtf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/emotes/wubtf.png
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/aaugh.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/aaugh.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/ayayajam.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/ayayajam.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/balddab.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/balddab.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/baldflick.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/baldflick.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/baldfloss.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/baldfloss.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/baldspin.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/baldspin.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/baldyappp.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/baldyappp.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/baldyikes.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/baldyikes.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/baners.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/baners.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/bropls.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/bropls.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/catjam.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/catjam.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/checkers.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/checkers.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/click.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/click.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/coomtime.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/coomtime.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/crawlers.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/crawlers.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/deadlole.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/deadlole.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/deskchan.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/deskchan.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/eato.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/eato.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/eddiebaldmansmash.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/eddiebaldmansmash.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/eddieknead.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/eddieknead.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/eddiespin.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/eddiespin.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/eekum.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/eekum.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/flappers.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/flappers.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/fubaldi.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/fubaldi.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/gamba.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/gamba.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/gawkgawk.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/gawkgawk.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/guitartime.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/guitartime.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/humpers.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/humpers.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/hypernodders.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/hypernodders.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/hypernopers.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/hypernopers.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/hyperpeepod.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/hyperpeepod.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/johnsouls.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/johnsouls.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/kissabrother.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/kissabrother.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/kissapregomie.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/kissapregomie.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/komodochomp.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/komodochomp.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/lgiggle.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/lgiggle.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/mariorun.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/mariorun.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/moon2bass.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/moon2bass.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/noted.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/noted.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/peepeegachat.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/peepeegachat.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/peepees.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/peepees.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/peepersd.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/peepersd.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/peepoboom.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/peepoboom.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/peepocheering.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/peepocheering.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/peepogolfclap.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/peepogolfclap.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/peeponarusprint.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/peeponarusprint.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/peeposhy.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/peeposhy.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/peeposteer.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/peeposteer.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/pepelepsy.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/pepelepsy.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/pepemetal.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/pepemetal.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/petthebaldie.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/petthebaldie.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/pettheeddie.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/pettheeddie.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/pettheqynoa.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/pettheqynoa.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/pukers.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/pukers.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/qynoalurks.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/qynoalurks.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/raremoon.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/raremoon.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/refracting.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/refracting.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/robpls.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/robpls.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/shruggers.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/shruggers.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/shushers.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/shushers.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/slap.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/slap.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/sneakers.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/sneakers.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/solarflare.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/solarflare.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/soulshroom.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/soulshroom.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/speeders.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/speeders.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/tanties.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/tanties.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/teatime.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/teatime.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/teatime2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/teatime2.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/tinyteeth.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/tinyteeth.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/twerkers.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/twerkers.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/vanish.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/vanish.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/vibers.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/vibers.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/wowers.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/wowers.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/assets/gifs/yappp.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/assets/gifs/yappp.gif
--------------------------------------------------------------------------------
/core-designsystem/src/main/kotlin/io/getstream/chat/android/twitchclone/designsystem/Themes.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.designsystem
18 |
19 | import androidx.compose.foundation.isSystemInDarkTheme
20 | import androidx.compose.runtime.Composable
21 | import androidx.compose.ui.graphics.Color
22 | import io.getstream.chat.android.compose.ui.theme.ChatTheme
23 | import io.getstream.chat.android.compose.ui.theme.StreamColors
24 | import io.getstream.video.android.compose.theme.VideoTheme
25 |
26 | val primaryColor = Color(0xFF6441a5)
27 | val shimmerBase: Color = Color(0xFF25282B)
28 | val shimmerHighlight: Color = Color(0xFFDFDEDE)
29 | val emojiColor: Color = Color(0xFFF4BC04)
30 |
31 | @Composable
32 | fun TwitchTheme(
33 | content: @Composable () -> Unit
34 | ) {
35 | ChatTheme(
36 | colors = if (isSystemInDarkTheme()) {
37 | StreamColors.defaultDarkColors().copy(
38 | primaryAccent = primaryColor
39 | )
40 | } else {
41 | StreamColors.defaultColors().copy(
42 | primaryAccent = primaryColor
43 | )
44 | }
45 | ) {
46 | VideoTheme(content = content)
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/core-designsystem/src/main/kotlin/io/getstream/chat/android/twitchclone/designsystem/TwitchLoadingIndicator.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.designsystem
18 |
19 | import androidx.compose.foundation.background
20 | import androidx.compose.foundation.layout.Box
21 | import androidx.compose.foundation.layout.fillMaxSize
22 | import androidx.compose.material.CircularProgressIndicator
23 | import androidx.compose.runtime.Composable
24 | import androidx.compose.ui.Alignment
25 | import androidx.compose.ui.Modifier
26 | import io.getstream.chat.android.compose.ui.theme.ChatTheme
27 |
28 | @Composable
29 | public fun TwitchLoadingIndicator() {
30 | Box(
31 | modifier = Modifier
32 | .fillMaxSize()
33 | .background(ChatTheme.colors.appBackground)
34 | ) {
35 | CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/core-designsystem/src/main/kotlin/io/getstream/chat/android/twitchclone/designsystem/assets/AssetUtils.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.designsystem.assets
18 |
19 | object AssetUtils {
20 |
21 | const val baseUrl = "file:///android_asset/"
22 |
23 | private const val gifExtension = ".gif"
24 |
25 | private const val gifFolder = "gifs"
26 |
27 | private const val emoteFolder = "emotes"
28 |
29 | fun getEmotePath(emote: String?): String {
30 | val folder = if (emote?.contains(gifExtension) == true) {
31 | gifFolder
32 | } else {
33 | emoteFolder
34 | }
35 | return "$baseUrl$folder/$emote"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/core-designsystem/src/main/kotlin/io/getstream/chat/android/twitchclone/designsystem/assets/AssetsProvider.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.designsystem.assets
18 |
19 | import android.content.Context
20 |
21 | object AssetsProvider {
22 |
23 | private val _userBadges = mutableMapOf()
24 | val userBadges: Map = _userBadges
25 |
26 | private val _reactions = mutableMapOf()
27 | val reactions: Map = _reactions
28 |
29 | fun loadBadges(context: Context) {
30 | val assets = context.assets ?: return
31 | val badges = assets.list("badges") as? Array ?: emptyArray()
32 |
33 | _userBadges += badges.map {
34 | val parts = it.split(".")
35 |
36 | parts[0] to it
37 | }
38 | }
39 |
40 | fun loadReactions(context: Context) {
41 | val assets = context.assets ?: return
42 |
43 | val gifs = assets.list("gifs") as? Array ?: emptyArray()
44 | val emotes = assets.list("emotes") as? Array ?: emptyArray()
45 |
46 | _reactions += (gifs + emotes).map {
47 | val parts = it.split(".")
48 |
49 | ":${parts[0]}:" to it
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/core-designsystem/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
24 |
25 |
26 |
33 |
37 |
41 |
42 |
43 |
44 |
51 |
52 |
--------------------------------------------------------------------------------
/core-designsystem/src/main/res/drawable/ic_emoji.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
23 |
26 |
27 |
--------------------------------------------------------------------------------
/core-designsystem/src/main/res/drawable/ic_half_moon.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
22 |
25 |
26 |
--------------------------------------------------------------------------------
/core-designsystem/src/main/res/drawable/ic_heart.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
22 |
26 |
27 |
--------------------------------------------------------------------------------
/core-designsystem/src/main/res/drawable/ic_info.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
22 |
25 |
26 |
--------------------------------------------------------------------------------
/core-designsystem/src/main/res/drawable/ic_sun.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
22 |
25 |
26 |
--------------------------------------------------------------------------------
/core-designsystem/src/main/res/drawable/ic_vertical_dots.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
22 |
25 |
26 |
--------------------------------------------------------------------------------
/core-designsystem/src/main/res/drawable/reward_ic.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
22 |
25 |
26 |
--------------------------------------------------------------------------------
/core-designsystem/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/core-designsystem/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/core-designsystem/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/core-designsystem/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/core-designsystem/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/core-designsystem/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/core-designsystem/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/core-designsystem/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/core-designsystem/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/core-designsystem/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/core-designsystem/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/core-designsystem/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/twitch-clone-compose/665963a27c1282f3226ae0994c9906d4623a30c5/core-designsystem/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/core-designsystem/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
22 |
23 |
--------------------------------------------------------------------------------
/core-designsystem/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 | #FF000000
19 | #FFFFFFFF
20 | #FF6441a5
21 |
22 |
--------------------------------------------------------------------------------
/core-designsystem/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 | twitch clone compose
19 |
20 | You are about to give this reward!
21 | Got it!
22 | Follow
23 |
24 |
25 | Reward %s
26 | Give reward %s for %d
27 | Expand emoji reactions
28 | Open chat settings
29 | %1$s\'s Rewards
30 | How to earn %1$s
31 | Followed!
32 | Send a message
33 | Live
34 | Failed to join this livestream channel.
35 | Your livestream is on the backstage now
36 | Video rendering failed
37 | Go Live
38 | Go Backstage
39 | Livestream has been started!
40 | Livestream has been ended. Bye bye~
41 |
42 |
--------------------------------------------------------------------------------
/core-designsystem/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
22 |
23 |
--------------------------------------------------------------------------------
/core-model/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/core-model/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | plugins {
17 | id("getstream.android.library")
18 | id("getstream.spotless")
19 | id("kotlin-parcelize")
20 | id("org.jetbrains.kotlin.plugin.serialization")
21 | }
22 |
23 | android {
24 | namespace = "io.getstream.chat.android.twitchclone.model"
25 | }
26 |
27 | dependencies {
28 | api(libs.stream.chat.client)
29 | api(libs.stream.video.core)
30 |
31 | api(libs.retrofit.kotlin.serialization)
32 | api(libs.kotlinx.serialization.json)
33 | compileOnly(libs.compose.stable.marker)
34 | }
35 |
--------------------------------------------------------------------------------
/core-model/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/core-model/src/main/kotlin/io/getstream/chat/android/twitchclone/model/Reward.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.model
18 |
19 | import androidx.compose.runtime.Immutable
20 | import kotlinx.serialization.Serializable
21 |
22 | @Immutable
23 | @Serializable
24 | data class Reward(
25 | val name: String,
26 | val color: String,
27 | val icon: String,
28 | val tokenAmount: Int
29 | )
30 |
--------------------------------------------------------------------------------
/core-navigation/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/core-navigation/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | plugins {
17 | id("getstream.android.library")
18 | id("getstream.android.library.compose")
19 | id("getstream.android.hilt")
20 | id("getstream.spotless")
21 | }
22 |
23 | android {
24 | namespace = "io.getstream.chat.android.twitchclone.navigation"
25 | }
26 |
27 | dependencies {
28 | implementation(libs.kotlinx.coroutines.android)
29 | api(libs.androidx.navigation.compose)
30 | }
31 |
--------------------------------------------------------------------------------
/core-navigation/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/core-navigation/src/main/kotlin/io/getstream/chat/android/twitchclone/navigation/LocalNavigation.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.navigation
18 |
19 | import androidx.compose.runtime.Composable
20 | import androidx.compose.runtime.ProvidableCompositionLocal
21 | import androidx.compose.runtime.ReadOnlyComposable
22 | import androidx.compose.runtime.compositionLocalOf
23 |
24 | public val LocalComposeNavigator: ProvidableCompositionLocal =
25 | compositionLocalOf {
26 | error(
27 | "No AppComposeNavigator provided! " +
28 | "Make sure to wrap all usages of UI components in TwitchTheme."
29 | )
30 | }
31 |
32 | /**
33 | * Retrieves the current [AppComposeNavigator] at the call site's position in the hierarchy.
34 | */
35 | public val currentComposeNavigator: AppComposeNavigator
36 | @Composable
37 | @ReadOnlyComposable
38 | get() = LocalComposeNavigator.current
39 |
--------------------------------------------------------------------------------
/core-navigation/src/main/kotlin/io/getstream/chat/android/twitchclone/navigation/NavigationCommand.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.navigation
18 |
19 | import androidx.navigation.NavOptions
20 |
21 | sealed class NavigationCommand {
22 | object NavigateUp : NavigationCommand()
23 | }
24 |
25 | sealed class ComposeNavigationCommand : NavigationCommand() {
26 | data class NavigateToRoute(val route: String, val options: NavOptions? = null) :
27 | ComposeNavigationCommand()
28 |
29 | data class NavigateUpWithResult(
30 | val key: String,
31 | val result: T,
32 | val route: String? = null
33 | ) : ComposeNavigationCommand()
34 |
35 | data class PopUpToRoute(val route: String, val inclusive: Boolean) : ComposeNavigationCommand()
36 | }
37 |
--------------------------------------------------------------------------------
/core-navigation/src/main/kotlin/io/getstream/chat/android/twitchclone/navigation/TwitchCloneComposeNavigator.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.navigation
18 |
19 | import androidx.navigation.NavOptionsBuilder
20 | import androidx.navigation.navOptions
21 | import javax.inject.Inject
22 |
23 | class TwitchCloneComposeNavigator @Inject constructor() : AppComposeNavigator() {
24 |
25 | override fun navigate(route: String, optionsBuilder: (NavOptionsBuilder.() -> Unit)?) {
26 | val options = optionsBuilder?.let { navOptions(it) }
27 | navigationCommands.tryEmit(ComposeNavigationCommand.NavigateToRoute(route, options))
28 | }
29 |
30 | override fun navigateAndClearBackStack(route: String) {
31 | navigationCommands.tryEmit(
32 | ComposeNavigationCommand.NavigateToRoute(
33 | route,
34 | navOptions {
35 | popUpTo(0)
36 | }
37 | )
38 | )
39 | }
40 |
41 | override fun popUpTo(route: String, inclusive: Boolean) {
42 | navigationCommands.tryEmit(ComposeNavigationCommand.PopUpToRoute(route, inclusive))
43 | }
44 |
45 | override fun navigateBackWithResult(
46 | key: String,
47 | result: T,
48 | route: String?
49 | ) {
50 | navigationCommands.tryEmit(
51 | ComposeNavigationCommand.NavigateUpWithResult(
52 | key = key,
53 | result = result,
54 | route = route
55 | )
56 | )
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/core-navigation/src/main/kotlin/io/getstream/chat/android/twitchclone/navigation/TwitchScreens.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.navigation
18 |
19 | import androidx.navigation.NamedNavArgument
20 | import androidx.navigation.NavType
21 | import androidx.navigation.navArgument
22 |
23 | sealed class TwitchScreens(
24 | val route: String,
25 | val navArguments: List = emptyList()
26 | ) {
27 | val name: String = route.appendArguments(navArguments)
28 |
29 | // home screen
30 | data object Channels : TwitchScreens("channels")
31 |
32 | // message screen
33 | data object Messages : TwitchScreens(
34 | route = "messages",
35 | navArguments = listOf(navArgument("channelId") { type = NavType.StringType })
36 | ) {
37 | fun createRoute(channelId: String) =
38 | name.replace("{${navArguments.first().name}}", channelId)
39 | }
40 |
41 | // livestream watcher screen
42 | data object LivestreamWatcher : TwitchScreens(
43 | route = "livestream_watcher",
44 | navArguments = listOf(navArgument("channelId") { type = NavType.StringType })
45 | ) {
46 | fun createRoute(channelId: String) =
47 | name.replace("{${navArguments.first().name}}", channelId)
48 | }
49 |
50 | // livestream streamer screen
51 | data object LivestreamStreamer : TwitchScreens(
52 | route = "livestream_host",
53 | navArguments = listOf(navArgument("channelId") { type = NavType.StringType })
54 | ) {
55 | fun createRoute(channelId: String) =
56 | name.replace("{${navArguments.first().name}}", channelId)
57 | }
58 | }
59 |
60 | private fun String.appendArguments(navArguments: List): String {
61 | val mandatoryArguments = navArguments.filter { it.argument.defaultValue == null }
62 | .takeIf { it.isNotEmpty() }
63 | ?.joinToString(separator = "/", prefix = "/") { "{${it.name}}" }
64 | .orEmpty()
65 | val optionalArguments = navArguments.filter { it.argument.defaultValue != null }
66 | .takeIf { it.isNotEmpty() }
67 | ?.joinToString(separator = "&", prefix = "?") { "${it.name}={${it.name}}" }
68 | .orEmpty()
69 | return "$this$mandatoryArguments$optionalArguments"
70 | }
71 |
--------------------------------------------------------------------------------
/core-network/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/core-network/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | plugins {
17 | id("getstream.android.library")
18 | id("getstream.android.hilt")
19 | id("getstream.spotless")
20 | id("org.jetbrains.kotlin.plugin.serialization")
21 | }
22 |
23 | android {
24 | namespace = "io.getstream.chat.android.twitchclone.network"
25 | }
26 |
27 | dependencies {
28 | implementation(project(":core-model"))
29 |
30 | api(libs.okhttp.logging)
31 | api(libs.retrofit.core)
32 | api(libs.sandwich.retrofit)
33 |
34 | api(libs.retrofit.kotlin.serialization)
35 | api(libs.kotlinx.serialization.json)
36 | }
37 |
--------------------------------------------------------------------------------
/core-network/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/core-network/src/main/kotlin/io/getstream/chat/android/twitchclone/network/TwitchDispatchers.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.network
18 |
19 | import javax.inject.Qualifier
20 | import kotlin.annotation.AnnotationRetention.RUNTIME
21 |
22 | @Qualifier
23 | @Retention(RUNTIME)
24 | annotation class Dispatcher(val twitchDispatchers: TwitchDispatchers)
25 |
26 | enum class TwitchDispatchers {
27 | IO
28 | }
29 |
--------------------------------------------------------------------------------
/core-network/src/main/kotlin/io/getstream/chat/android/twitchclone/network/di/DispatchersModule.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.network.di
18 |
19 | import dagger.Module
20 | import dagger.Provides
21 | import dagger.hilt.InstallIn
22 | import dagger.hilt.components.SingletonComponent
23 | import io.getstream.chat.android.twitchclone.network.Dispatcher
24 | import io.getstream.chat.android.twitchclone.network.TwitchDispatchers
25 | import kotlinx.coroutines.CoroutineDispatcher
26 | import kotlinx.coroutines.Dispatchers
27 |
28 | @Module
29 | @InstallIn(SingletonComponent::class)
30 | internal object DispatchersModule {
31 |
32 | @Provides
33 | @Dispatcher(TwitchDispatchers.IO)
34 | fun providesIODispatcher(): CoroutineDispatcher = Dispatchers.IO
35 | }
36 |
--------------------------------------------------------------------------------
/core-network/src/main/kotlin/io/getstream/chat/android/twitchclone/network/di/NetworkModule.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.network.di
18 |
19 | import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
20 | import com.skydoves.sandwich.retrofit.adapters.ApiResponseCallAdapterFactory
21 | import dagger.Module
22 | import dagger.Provides
23 | import dagger.hilt.InstallIn
24 | import dagger.hilt.components.SingletonComponent
25 | import io.getstream.chat.android.twitchclone.network.service.RewardsService
26 | import javax.inject.Singleton
27 | import kotlinx.serialization.json.Json
28 | import okhttp3.MediaType.Companion.toMediaType
29 | import retrofit2.Retrofit
30 | import retrofit2.create
31 |
32 | @Module
33 | @InstallIn(SingletonComponent::class)
34 | internal object NetworkModule {
35 |
36 | @Provides
37 | @Singleton
38 | fun providesNetworkJson(): Json = Json {
39 | ignoreUnknownKeys = true
40 | }
41 |
42 | @Provides
43 | @Singleton
44 | fun provideTwitchRetrofit(networkJson: Json): Retrofit {
45 | return Retrofit.Builder()
46 | .baseUrl(
47 | "https://gist.githubusercontent.com/skydoves/c2da9e382222ba50aba7a01fcace76e1/" +
48 | "raw/d87a6fdfa4cff479d8dae7b32ac19a0c6d16817a/"
49 | )
50 | .addConverterFactory(networkJson.asConverterFactory("application/json".toMediaType()))
51 | .addCallAdapterFactory(ApiResponseCallAdapterFactory.create())
52 | .build()
53 | }
54 |
55 | @Provides
56 | @Singleton
57 | fun provideRewardsService(
58 | retrofit: Retrofit
59 | ): RewardsService {
60 | return retrofit.create()
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/core-network/src/main/kotlin/io/getstream/chat/android/twitchclone/network/service/RewardsService.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.network.service
18 |
19 | import com.skydoves.sandwich.ApiResponse
20 | import io.getstream.chat.android.twitchclone.model.Reward
21 | import retrofit2.http.GET
22 |
23 | interface RewardsService {
24 |
25 | @GET("TwitchCloneRewards.json")
26 | suspend fun fetchRewards(): ApiResponse>
27 | }
28 |
--------------------------------------------------------------------------------
/feature-channels/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/feature-channels/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | @Suppress("DSL_SCOPE_VIOLATION")
17 | plugins {
18 | id("getstream.android.library")
19 | id("getstream.android.library.compose")
20 | id("getstream.android.feature")
21 | id("getstream.android.hilt")
22 | id("getstream.spotless")
23 | }
24 |
25 | android {
26 | namespace = "io.getstream.chat.android.twitchclone.channels"
27 | }
28 |
29 | dependencies {
30 | // Stream SDK
31 | implementation(libs.stream.chat.compose)
32 |
33 | // Compose
34 | implementation(libs.androidx.compose.ui)
35 | implementation(libs.androidx.compose.ui.tooling)
36 | implementation(libs.androidx.compose.foundation)
37 | implementation(libs.androidx.compose.material)
38 | implementation(libs.androidx.compose.runtime)
39 | }
40 |
--------------------------------------------------------------------------------
/feature-channels/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/feature-channels/src/main/kotlin/io/getstream/chat/android/twitchclone/channels/StreamerInformation.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.channels
18 |
19 | import androidx.compose.foundation.layout.Arrangement
20 | import androidx.compose.foundation.layout.Row
21 | import androidx.compose.foundation.layout.Spacer
22 | import androidx.compose.foundation.layout.size
23 | import androidx.compose.foundation.layout.width
24 | import androidx.compose.foundation.layout.wrapContentSize
25 | import androidx.compose.foundation.shape.CircleShape
26 | import androidx.compose.material.Text
27 | import androidx.compose.runtime.Composable
28 | import androidx.compose.ui.Alignment
29 | import androidx.compose.ui.Modifier
30 | import androidx.compose.ui.draw.clip
31 | import androidx.compose.ui.layout.ContentScale
32 | import androidx.compose.ui.text.font.FontWeight
33 | import androidx.compose.ui.unit.dp
34 | import androidx.compose.ui.unit.sp
35 | import com.skydoves.landscapist.ImageOptions
36 | import com.skydoves.landscapist.animation.crossfade.CrossfadePlugin
37 | import com.skydoves.landscapist.coil.CoilImage
38 | import com.skydoves.landscapist.components.rememberImageComponent
39 | import io.getstream.chat.android.compose.ui.theme.ChatTheme
40 |
41 | @Composable
42 | fun StreamerInformation(
43 | streamerAvatarImage: String?,
44 | streamerName: String?,
45 | modifier: Modifier = Modifier,
46 | verticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
47 | horizontalArrangement: Arrangement.Horizontal = Arrangement.Center
48 | ) {
49 | Row(
50 | modifier = modifier,
51 | verticalAlignment = verticalAlignment,
52 | horizontalArrangement = horizontalArrangement
53 | ) {
54 | CoilImage(
55 | modifier = Modifier
56 | .size(24.dp)
57 | .clip(CircleShape),
58 | imageModel = { streamerAvatarImage },
59 | imageOptions = ImageOptions(contentScale = ContentScale.Crop),
60 | component = rememberImageComponent {
61 | +CrossfadePlugin()
62 | }
63 | )
64 |
65 | Spacer(modifier = Modifier.width(6.dp))
66 |
67 | if (streamerName != null) {
68 | Text(
69 | modifier = Modifier.wrapContentSize(),
70 | text = streamerName,
71 | style = ChatTheme.typography.bodyBold,
72 | fontSize = 14.sp,
73 | color = ChatTheme.colors.textHighEmphasis,
74 | fontWeight = FontWeight.Bold
75 | )
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/feature-livestream/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/feature-livestream/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | @Suppress("DSL_SCOPE_VIOLATION")
17 | plugins {
18 | id("getstream.android.library")
19 | id("getstream.android.library.compose")
20 | id("getstream.android.feature")
21 | id("getstream.android.hilt")
22 | id("getstream.spotless")
23 | }
24 |
25 | android {
26 | namespace = "io.getstream.chat.android.twitchclone.livestream"
27 | }
28 |
29 | dependencies {
30 | // feature module
31 | implementation(project(":feature-messages"))
32 |
33 | // Stream SDK
34 | implementation(libs.stream.chat.compose)
35 | implementation(libs.stream.video.compose)
36 |
37 | // accompanist
38 | implementation(libs.accompanist.permissions)
39 |
40 | // Compose
41 | implementation(libs.androidx.compose.ui)
42 | implementation(libs.androidx.compose.ui.tooling)
43 | implementation(libs.androidx.compose.foundation)
44 | implementation(libs.androidx.compose.material)
45 | implementation(libs.androidx.compose.runtime)
46 | }
47 |
--------------------------------------------------------------------------------
/feature-livestream/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/feature-livestream/src/main/kotlin/io/getstream/chat/android/twitchclone/livestream/EnsurePermissions.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.livestream
18 |
19 | import android.Manifest
20 | import android.os.Build
21 | import androidx.compose.runtime.Composable
22 | import androidx.compose.runtime.LaunchedEffect
23 | import com.google.accompanist.permissions.ExperimentalPermissionsApi
24 | import com.google.accompanist.permissions.rememberMultiplePermissionsState
25 |
26 | @OptIn(ExperimentalPermissionsApi::class)
27 | @Composable
28 | fun EnsureVideoCallPermissions(onPermissionsGranted: () -> Unit) {
29 | // While the SDK will handle the microphone permission,
30 | // its not a bad idea to do it prior to entering any call UIs
31 | val permissionsState = rememberMultiplePermissionsState(
32 | permissions = buildList {
33 | // Access to camera & microphone
34 | add(Manifest.permission.CAMERA)
35 | add(Manifest.permission.RECORD_AUDIO)
36 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
37 | // Allow for foreground service for notification on API 26+
38 | add(Manifest.permission.FOREGROUND_SERVICE)
39 | }
40 | }
41 | )
42 |
43 | LaunchedEffect(key1 = Unit) {
44 | permissionsState.launchMultiplePermissionRequest()
45 | }
46 |
47 | LaunchedEffect(key1 = permissionsState.allPermissionsGranted) {
48 | if (permissionsState.allPermissionsGranted) {
49 | onPermissionsGranted()
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/feature-livestream/src/main/kotlin/io/getstream/chat/android/twitchclone/livestream/LivestreamViewModel.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.livestream
18 |
19 | import androidx.lifecycle.ViewModel
20 | import io.getstream.video.android.core.Call
21 | import io.getstream.video.android.core.StreamVideo
22 | import kotlinx.coroutines.flow.MutableStateFlow
23 | import kotlinx.coroutines.flow.StateFlow
24 |
25 | class LivestreamViewModel : ViewModel() {
26 |
27 | private val livestreamUiStateMutableState =
28 | MutableStateFlow(LivestreamUiState.Loading)
29 | val livestreamUiState: StateFlow = livestreamUiStateMutableState
30 |
31 | suspend fun joinCall(type: String, id: String) {
32 | val streamVideo = StreamVideo.instance()
33 | val activeCall = streamVideo.state.activeCall.value
34 | val call = if (activeCall != null) {
35 | if (activeCall.id != id) {
36 | // If the call id is different leave the previous call
37 | activeCall.leave()
38 | // Return a new call
39 | streamVideo.call(type = type, id = id)
40 | } else {
41 | // Call ID is the same, use the active call
42 | activeCall
43 | }
44 | } else {
45 | // There is no active call, create new call
46 | streamVideo.call(type = type, id = id)
47 | }
48 | val result = call.join(create = true)
49 | result.onSuccess {
50 | livestreamUiStateMutableState.value = LivestreamUiState.Success(call)
51 | }.onError {
52 | livestreamUiStateMutableState.value = LivestreamUiState.Error
53 | }
54 | }
55 |
56 | override fun onCleared() {
57 | super.onCleared()
58 | }
59 | }
60 |
61 | sealed interface LivestreamUiState {
62 |
63 | data object Loading : LivestreamUiState
64 |
65 | data class Success(val call: Call) : LivestreamUiState
66 |
67 | data object Error : LivestreamUiState
68 | }
69 |
--------------------------------------------------------------------------------
/feature-messages/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/feature-messages/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | @Suppress("DSL_SCOPE_VIOLATION")
17 | plugins {
18 | id("getstream.android.library")
19 | id("getstream.android.library.compose")
20 | id("getstream.android.feature")
21 | id("getstream.android.hilt")
22 | id("getstream.spotless")
23 | }
24 |
25 | android {
26 | namespace = "io.getstream.chat.android.twitchclone.messages"
27 | }
28 |
29 | dependencies {
30 | // Stream SDK
31 | implementation(libs.stream.chat.compose)
32 |
33 | // Compose
34 | implementation(libs.androidx.compose.ui)
35 | implementation(libs.androidx.compose.ui.tooling)
36 | implementation(libs.androidx.compose.foundation)
37 | implementation(libs.androidx.compose.material)
38 | implementation(libs.androidx.compose.runtime)
39 | }
40 |
--------------------------------------------------------------------------------
/feature-messages/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/feature-messages/src/main/kotlin/io/getstream/chat/android/twitchclone/messages/extensions/MessageExtensions.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.chat.android.twitchclone.messages.extensions
18 |
19 | import androidx.compose.foundation.layout.fillMaxSize
20 | import androidx.compose.foundation.layout.padding
21 | import androidx.compose.foundation.text.InlineTextContent
22 | import androidx.compose.foundation.text.appendInlineContent
23 | import androidx.compose.ui.Modifier
24 | import androidx.compose.ui.text.AnnotatedString
25 | import androidx.compose.ui.text.Placeholder
26 | import androidx.compose.ui.text.PlaceholderVerticalAlign
27 | import androidx.compose.ui.text.buildAnnotatedString
28 | import androidx.compose.ui.unit.dp
29 | import androidx.compose.ui.unit.sp
30 | import com.skydoves.landscapist.coil.CoilImage
31 | import io.getstream.chat.android.twitchclone.designsystem.assets.AssetUtils
32 | import io.getstream.chat.android.twitchclone.designsystem.assets.AssetsProvider
33 |
34 | fun String.transformText(): Pair