diff --git a/app/build.gradle b/app/build.gradle
index a327a5d..4bff9ca 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -40,6 +40,7 @@ dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
+ implementation 'androidx.recyclerview:recyclerview:1.3.2'
// ExoPlayer para reproducción de video
implementation 'com.google.android.exoplayer:exoplayer:2.18.7'
diff --git a/app/build/outputs/apk/release/app-release.apk b/app/build/outputs/apk/release/app-release.apk
deleted file mode 100644
index 53c234a..0000000
Binary files a/app/build/outputs/apk/release/app-release.apk and /dev/null differ
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 65a6079..a947d5c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -15,12 +15,17 @@
android:theme="@style/Theme.StreamPlayer"
android:usesCleartextTraffic="true">
+
+
+ android:exported="true">
+
diff --git a/app/src/main/java/com/streamplayer/ChannelAdapter.java b/app/src/main/java/com/streamplayer/ChannelAdapter.java
new file mode 100644
index 0000000..3f348ef
--- /dev/null
+++ b/app/src/main/java/com/streamplayer/ChannelAdapter.java
@@ -0,0 +1,63 @@
+package com.streamplayer;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.List;
+
+public class ChannelAdapter extends RecyclerView.Adapter {
+
+ public interface OnChannelClickListener {
+ void onChannelClick(StreamChannel channel);
+ }
+
+ private final List channels;
+ private final OnChannelClickListener listener;
+
+ public ChannelAdapter(List channels, OnChannelClickListener listener) {
+ this.channels = channels;
+ this.listener = listener;
+ }
+
+ @NonNull
+ @Override
+ public ChannelViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.item_channel, parent, false);
+ return new ChannelViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ChannelViewHolder holder, int position) {
+ StreamChannel channel = channels.get(position);
+ holder.name.setText(channel.getName());
+ holder.icon.setImageResource(R.drawable.ic_channel_default);
+ holder.itemView.setOnClickListener(v -> {
+ if (listener != null) {
+ listener.onChannelClick(channel);
+ }
+ });
+ }
+
+ @Override
+ public int getItemCount() {
+ return channels.size();
+ }
+
+ static class ChannelViewHolder extends RecyclerView.ViewHolder {
+ final ImageView icon;
+ final TextView name;
+
+ ChannelViewHolder(@NonNull View itemView) {
+ super(itemView);
+ icon = itemView.findViewById(R.id.channel_icon);
+ name = itemView.findViewById(R.id.channel_name);
+ }
+ }
+}
diff --git a/app/src/main/java/com/streamplayer/ChannelRepository.java b/app/src/main/java/com/streamplayer/ChannelRepository.java
new file mode 100644
index 0000000..bfeec39
--- /dev/null
+++ b/app/src/main/java/com/streamplayer/ChannelRepository.java
@@ -0,0 +1,84 @@
+package com.streamplayer;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public final class ChannelRepository {
+
+ private static final List CHANNELS = Collections.unmodifiableList(Arrays.asList(
+ new StreamChannel("ESPN", "https://streamtpmedia.com/global2.php?stream=espn"),
+ new StreamChannel("ESPN 2", "https://streamtpmedia.com/global2.php?stream=espn2"),
+ new StreamChannel("ESPN 3", "https://streamtpmedia.com/global2.php?stream=espn3"),
+ new StreamChannel("ESPN 4", "https://streamtpmedia.com/global2.php?stream=espn4"),
+ new StreamChannel("ESPN 3 MX", "https://streamtpmedia.com/global2.php?stream=espn3mx"),
+ new StreamChannel("ESPN 5", "https://streamtpmedia.com/global2.php?stream=espn5"),
+ new StreamChannel("Fox Sports 3 MX", "https://streamtpmedia.com/global2.php?stream=foxsports3mx"),
+ new StreamChannel("ESPN 6", "https://streamtpmedia.com/global2.php?stream=espn6"),
+ new StreamChannel("Fox Sports MX", "https://streamtpmedia.com/global2.php?stream=foxsportsmx"),
+ new StreamChannel("ESPN 7", "https://streamtpmedia.com/global2.php?stream=espn7"),
+ new StreamChannel("Azteca Deportes", "https://streamtpmedia.com/global2.php?stream=azteca_deportes"),
+ new StreamChannel("Win Plus", "https://streamtpmedia.com/global2.php?stream=winplus"),
+ new StreamChannel("DAZN 1", "https://streamtpmedia.com/global2.php?stream=dazn1"),
+ new StreamChannel("Win Plus 2", "https://streamtpmedia.com/global2.php?stream=winplus2"),
+ new StreamChannel("DAZN 2", "https://streamtpmedia.com/global2.php?stream=dazn2"),
+ new StreamChannel("Win Sports", "https://streamtpmedia.com/global2.php?stream=winsports"),
+ new StreamChannel("DAZN LaLiga", "https://streamtpmedia.com/global2.php?stream=dazn_laliga"),
+ new StreamChannel("Win Plus Online 1", "https://streamtpmedia.com/global2.php?stream=winplusonline1"),
+ new StreamChannel("Caracol TV", "https://streamtpmedia.com/global2.php?stream=caracoltv"),
+ new StreamChannel("Fox 1 AR", "https://streamtpmedia.com/global2.php?stream=fox1ar"),
+ new StreamChannel("Fox 2 USA", "https://streamtpmedia.com/global2.php?stream=fox_2_usa"),
+ new StreamChannel("Fox 2 AR", "https://streamtpmedia.com/global2.php?stream=fox2ar"),
+ new StreamChannel("TNT 1 GB", "https://streamtpmedia.com/global2.php?stream=tnt_1_gb"),
+ new StreamChannel("TNT 2 GB", "https://streamtpmedia.com/global2.php?stream=tnt_2_gb"),
+ new StreamChannel("Fox 3 AR", "https://streamtpmedia.com/global2.php?stream=fox3ar"),
+ new StreamChannel("Universo USA", "https://streamtpmedia.com/global2.php?stream=universo_usa"),
+ new StreamChannel("DSports", "https://streamtpmedia.com/global2.php?stream=dsports"),
+ new StreamChannel("Univision USA", "https://streamtpmedia.com/global2.php?stream=univision_usa"),
+ new StreamChannel("DSports 2", "https://streamtpmedia.com/global2.php?stream=dsports2"),
+ new StreamChannel("Fox Deportes USA", "https://streamtpmedia.com/global2.php?stream=fox_deportes_usa"),
+ new StreamChannel("DSports Plus", "https://streamtpmedia.com/global2.php?stream=dsportsplus"),
+ new StreamChannel("Fox Sports 2 MX", "https://streamtpmedia.com/global2.php?stream=foxsports2mx"),
+ new StreamChannel("TNT Sports Chile", "https://streamtpmedia.com/global2.php?stream=tntsportschile"),
+ new StreamChannel("Fox Sports Premium", "https://streamtpmedia.com/global2.php?stream=foxsportspremium"),
+ new StreamChannel("TNT Sports", "https://streamtpmedia.com/global2.php?stream=tntsports"),
+ new StreamChannel("ESPN MX", "https://streamtpmedia.com/global2.php?stream=espnmx"),
+ new StreamChannel("ESPN Premium", "https://streamtpmedia.com/global2.php?stream=espnpremium"),
+ new StreamChannel("ESPN 2 MX", "https://streamtpmedia.com/global2.php?stream=espn2mx"),
+ new StreamChannel("TyC Sports", "https://streamtpmedia.com/global2.php?stream=tycsports"),
+ new StreamChannel("TUDN USA", "https://streamtpmedia.com/global2.php?stream=tudn_usa"),
+ new StreamChannel("Telefe", "https://streamtpmedia.com/global2.php?stream=telefe"),
+ new StreamChannel("TNT 3 GB", "https://streamtpmedia.com/global2.php?stream=tnt_3_gb"),
+ new StreamChannel("TV Pública", "https://streamtpmedia.com/global2.php?stream=tv_publica"),
+ new StreamChannel("Fox 1 USA", "https://streamtpmedia.com/global2.php?stream=fox_1_usa"),
+ new StreamChannel("Liga 1 Max", "https://streamtpmedia.com/global2.php?stream=liga1max"),
+ new StreamChannel("Gol TV", "https://streamtpmedia.com/global2.php?stream=goltv"),
+ new StreamChannel("VTV Plus", "https://streamtpmedia.com/global2.php?stream=vtvplus"),
+ new StreamChannel("ESPN Deportes", "https://streamtpmedia.com/global2.php?stream=espndeportes"),
+ new StreamChannel("Gol Perú", "https://streamtpmedia.com/global2.php?stream=golperu"),
+ new StreamChannel("TNT 4 GB", "https://streamtpmedia.com/global2.php?stream=tnt_4_gb"),
+ new StreamChannel("SportTV BR 1", "https://streamtpmedia.com/global2.php?stream=sporttvbr1"),
+ new StreamChannel("SportTV BR 2", "https://streamtpmedia.com/global2.php?stream=sporttvbr2"),
+ new StreamChannel("SportTV BR 3", "https://streamtpmedia.com/global2.php?stream=sporttvbr3"),
+ new StreamChannel("Premiere 1", "https://streamtpmedia.com/global2.php?stream=premiere1"),
+ new StreamChannel("Premiere 2", "https://streamtpmedia.com/global2.php?stream=premiere2"),
+ new StreamChannel("Premiere 3", "https://streamtpmedia.com/global2.php?stream=premiere3"),
+ new StreamChannel("ESPN NL 1", "https://streamtpmedia.com/global2.php?stream=espn_nl1"),
+ new StreamChannel("ESPN NL 2", "https://streamtpmedia.com/global2.php?stream=espn_nl2"),
+ new StreamChannel("ESPN NL 3", "https://streamtpmedia.com/global2.php?stream=espn_nl3"),
+ new StreamChannel("Caliente TV MX", "https://streamtpmedia.com/global2.php?stream=calientetvmx"),
+ new StreamChannel("USA Network", "https://streamtpmedia.com/global2.php?stream=usa_network"),
+ new StreamChannel("TyC Internacional", "https://streamtpmedia.com/global2.php?stream=tycinternacional"),
+ new StreamChannel("Canal 5 MX", "https://streamtpmedia.com/global2.php?stream=canal5mx"),
+ new StreamChannel("TUDN MX", "https://streamtpmedia.com/global2.php?stream=TUDNMX"),
+ new StreamChannel("FUTV", "https://streamtpmedia.com/global2.php?stream=futv"),
+ new StreamChannel("LaLiga Hypermotion", "https://streamtpmedia.com/global2.php?stream=laligahypermotion")
+ ));
+
+ private ChannelRepository() {
+ }
+
+ public static List getChannels() {
+ return CHANNELS;
+ }
+}
diff --git a/app/src/main/java/com/streamplayer/MainActivity.java b/app/src/main/java/com/streamplayer/MainActivity.java
index d3a92d5..a837062 100644
--- a/app/src/main/java/com/streamplayer/MainActivity.java
+++ b/app/src/main/java/com/streamplayer/MainActivity.java
@@ -1,157 +1,29 @@
package com.streamplayer;
+import android.content.Intent;
import android.os.Bundle;
-import android.os.StrictMode;
-import android.view.View;
-import android.widget.ProgressBar;
-import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
-
-import com.google.android.exoplayer2.ExoPlayer;
-import com.google.android.exoplayer2.MediaItem;
-import com.google.android.exoplayer2.PlaybackException;
-import com.google.android.exoplayer2.Player;
-import com.google.android.exoplayer2.ui.PlayerView;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
public class MainActivity extends AppCompatActivity {
- private ExoPlayer player;
- private PlayerView playerView;
- private ProgressBar loadingIndicator;
- private TextView errorMessage;
-
- private static final String STREAM_PAGE_URL = "https://streamtpmedia.com/global2.php?stream=espn";
-
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
- // Configurar política de red para allow cleartext traffic
- StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
- StrictMode.setThreadPolicy(policy);
-
setContentView(R.layout.activity_main);
- initViews();
-
- // Configurar DNS de Google para streaming
- DNSSetter.configureDNSToGoogle(this);
-
- initializePlayer();
- }
-
- private void initViews() {
- playerView = findViewById(R.id.player_view);
- loadingIndicator = findViewById(R.id.loading_indicator);
- errorMessage = findViewById(R.id.error_message);
- }
-
- private void initializePlayer() {
- showLoading(true);
- new Thread(() -> {
- try {
- String resolvedUrl = StreamUrlResolver.resolve(STREAM_PAGE_URL);
- runOnUiThread(() -> startPlayback(resolvedUrl));
- } catch (Exception e) {
- runOnUiThread(() -> showError("Error al obtener stream: " + e.getMessage()));
- }
- }).start();
- }
-
- private void startPlayback(String streamUrl) {
- try {
- releasePlayer();
- player = new ExoPlayer.Builder(this).build();
- playerView.setPlayer(player);
-
- player.addListener(new Player.Listener() {
- @Override
- public void onPlaybackStateChanged(int playbackState) {
- switch (playbackState) {
- case Player.STATE_BUFFERING:
- showLoading(true);
- break;
- case Player.STATE_READY:
- showLoading(false);
- break;
- case Player.STATE_ENDED:
- // Video terminado
- break;
- }
- }
-
- @Override
- public void onPlayerError(PlaybackException error) {
- showError("Error al reproducir: " + error.getMessage());
- }
- });
-
- MediaItem mediaItem = MediaItem.fromUri(streamUrl);
- player.setMediaItem(mediaItem);
- player.prepare();
- player.setPlayWhenReady(true);
-
- } catch (Exception e) {
- showError("Error al inicializar reproductor: " + e.getMessage());
- }
- }
-
- private void showLoading(boolean show) {
- loadingIndicator.setVisibility(show ? View.VISIBLE : View.GONE);
- errorMessage.setVisibility(View.GONE);
- playerView.setVisibility(show ? View.GONE : View.VISIBLE);
- }
-
- private void showError(String message) {
- loadingIndicator.setVisibility(View.GONE);
- playerView.setVisibility(View.GONE);
- errorMessage.setVisibility(View.VISIBLE);
- errorMessage.setText(message);
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- if (player != null) {
- playerView.onResume();
- }
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- if (player != null) {
- playerView.onResume();
- }
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- if (player != null) {
- playerView.onPause();
- }
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- if (player != null) {
- playerView.onPause();
- }
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- releasePlayer();
- }
-
- private void releasePlayer() {
- if (player != null) {
- player.release();
- player = null;
- }
+ RecyclerView recyclerView = findViewById(R.id.channel_grid);
+ recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
+ ChannelAdapter adapter = new ChannelAdapter(
+ ChannelRepository.getChannels(),
+ channel -> {
+ Intent intent = new Intent(MainActivity.this, PlayerActivity.class);
+ intent.putExtra(PlayerActivity.EXTRA_CHANNEL_NAME, channel.getName());
+ intent.putExtra(PlayerActivity.EXTRA_CHANNEL_URL, channel.getPageUrl());
+ startActivity(intent);
+ });
+ recyclerView.setAdapter(adapter);
}
}
diff --git a/app/src/main/java/com/streamplayer/PlayerActivity.java b/app/src/main/java/com/streamplayer/PlayerActivity.java
new file mode 100644
index 0000000..f439fea
--- /dev/null
+++ b/app/src/main/java/com/streamplayer/PlayerActivity.java
@@ -0,0 +1,203 @@
+package com.streamplayer;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.StrictMode;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import androidx.appcompat.app.AppCompatActivity;
+
+import com.google.android.exoplayer2.ExoPlayer;
+import com.google.android.exoplayer2.MediaItem;
+import com.google.android.exoplayer2.PlaybackException;
+import com.google.android.exoplayer2.Player;
+import com.google.android.exoplayer2.ui.PlayerView;
+
+public class PlayerActivity extends AppCompatActivity {
+
+ public static final String EXTRA_CHANNEL_NAME = "extra_channel_name";
+ public static final String EXTRA_CHANNEL_URL = "extra_channel_url";
+
+ private PlayerView playerView;
+ private ProgressBar loadingIndicator;
+ private TextView errorMessage;
+ private TextView channelLabel;
+ private Button closeButton;
+ private View playerToolbar;
+
+ private ExoPlayer player;
+ private String channelName;
+ private String channelUrl;
+ private boolean overlayVisible = true;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ StrictMode.setThreadPolicy(
+ new StrictMode.ThreadPolicy.Builder().permitAll().build()
+ );
+
+ setContentView(R.layout.activity_player);
+
+ Intent intent = getIntent();
+ if (intent == null) {
+ finish();
+ return;
+ }
+
+ channelName = intent.getStringExtra(EXTRA_CHANNEL_NAME);
+ channelUrl = intent.getStringExtra(EXTRA_CHANNEL_URL);
+
+ if (channelName == null || channelUrl == null) {
+ finish();
+ return;
+ }
+
+ initViews();
+ channelLabel.setText(channelName);
+
+ DNSSetter.configureDNSToGoogle(this);
+ loadChannel();
+ }
+
+ private void initViews() {
+ playerView = findViewById(R.id.player_view);
+ loadingIndicator = findViewById(R.id.loading_indicator);
+ errorMessage = findViewById(R.id.error_message);
+ channelLabel = findViewById(R.id.player_channel_label);
+ closeButton = findViewById(R.id.close_button);
+ playerToolbar = findViewById(R.id.player_toolbar);
+
+ closeButton.setOnClickListener(v -> finish());
+ playerView.setOnClickListener(v -> toggleOverlay());
+ }
+
+ private void loadChannel() {
+ showLoading(true);
+ new Thread(() -> {
+ try {
+ String resolvedUrl = StreamUrlResolver.resolve(channelUrl);
+ runOnUiThread(() -> startPlayback(resolvedUrl));
+ } catch (Exception e) {
+ runOnUiThread(() -> showError("Error al obtener stream: " + e.getMessage()));
+ }
+ }).start();
+ }
+
+ private void startPlayback(String streamUrl) {
+ try {
+ releasePlayer();
+ player = new ExoPlayer.Builder(this).build();
+ playerView.setPlayer(player);
+
+ player.addListener(new Player.Listener() {
+ @Override
+ public void onPlaybackStateChanged(int playbackState) {
+ if (playbackState == Player.STATE_READY) {
+ showLoading(false);
+ } else if (playbackState == Player.STATE_BUFFERING) {
+ showLoading(true);
+ }
+ }
+
+ @Override
+ public void onPlayerError(PlaybackException error) {
+ showError("Error al reproducir: " + error.getMessage());
+ }
+ });
+
+ MediaItem mediaItem = MediaItem.fromUri(streamUrl);
+ player.setMediaItem(mediaItem);
+ player.prepare();
+ player.setPlayWhenReady(true);
+ setOverlayVisible(false);
+
+ } catch (Exception e) {
+ showError("Error al inicializar reproductor: " + e.getMessage());
+ }
+ }
+
+ private void showLoading(boolean show) {
+ loadingIndicator.setVisibility(show ? View.VISIBLE : View.GONE);
+ errorMessage.setVisibility(View.GONE);
+ playerView.setVisibility(show ? View.GONE : View.VISIBLE);
+ if (show) {
+ setOverlayVisible(true);
+ }
+ }
+
+ private void showError(String message) {
+ loadingIndicator.setVisibility(View.GONE);
+ playerView.setVisibility(View.GONE);
+ errorMessage.setVisibility(View.VISIBLE);
+ errorMessage.setText(message);
+ setOverlayVisible(true);
+ }
+
+ private void releasePlayer() {
+ if (player != null) {
+ player.release();
+ player = null;
+ }
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ if (player != null) {
+ playerView.onResume();
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ if (player != null) {
+ playerView.onResume();
+ }
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ if (player != null) {
+ playerView.onPause();
+ }
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ if (player != null) {
+ playerView.onPause();
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ releasePlayer();
+ }
+
+ private void toggleOverlay() {
+ setOverlayVisible(!overlayVisible);
+ }
+
+ private void setOverlayVisible(boolean visible) {
+ overlayVisible = visible;
+ playerToolbar.setVisibility(visible ? View.VISIBLE : View.GONE);
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (!overlayVisible) {
+ setOverlayVisible(true);
+ } else {
+ super.onBackPressed();
+ }
+ }
+}
diff --git a/app/src/main/java/com/streamplayer/StreamChannel.java b/app/src/main/java/com/streamplayer/StreamChannel.java
new file mode 100644
index 0000000..beb6025
--- /dev/null
+++ b/app/src/main/java/com/streamplayer/StreamChannel.java
@@ -0,0 +1,19 @@
+package com.streamplayer;
+
+public class StreamChannel {
+ private final String name;
+ private final String pageUrl;
+
+ public StreamChannel(String name, String pageUrl) {
+ this.name = name;
+ this.pageUrl = pageUrl;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getPageUrl() {
+ return pageUrl;
+ }
+}
diff --git a/app/src/main/res/drawable/bg_channel_item.xml b/app/src/main/res/drawable/bg_channel_item.xml
new file mode 100644
index 0000000..359e8fd
--- /dev/null
+++ b/app/src/main/res/drawable/bg_channel_item.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_channel_default.xml b/app/src/main/res/drawable/ic_channel_default.xml
new file mode 100644
index 0000000..4d3663b
--- /dev/null
+++ b/app/src/main/res/drawable/ic_channel_default.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 2b6b475..c09eba1 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -7,35 +7,32 @@
android:background="@color/black"
tools:context=".MainActivity">
-
-
-
-
+
+
diff --git a/app/src/main/res/layout/activity_player.xml b/app/src/main/res/layout/activity_player.xml
new file mode 100644
index 0000000..1dc7f3f
--- /dev/null
+++ b/app/src/main/res/layout/activity_player.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/item_channel.xml b/app/src/main/res/layout/item_channel.xml
new file mode 100644
index 0000000..a088452
--- /dev/null
+++ b/app/src/main/res/layout/item_channel.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+