Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto
113 changes: 113 additions & 0 deletions AddPlaylistFragment.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package com.pitv.player.ui;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.widget.ViewPager2;

import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import com.pitv.player.R;
import com.pitv.player.adapter.PlaylistTabAdapter;
import com.pitv.player.model.Playlist;
import com.pitv.player.service.PlaylistManager;

/**
* Fragment para adicionar uma nova playlist
*/
public class AddPlaylistFragment extends Fragment implements
M3UInputFragment.OnM3UAddListener,
XtreamInputFragment.OnXtreamAddListener {

private TabLayout tabLayout;
private ViewPager2 viewPager;
private PlaylistTabAdapter tabAdapter;
private PlaylistManager playlistManager;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
playlistManager = PlaylistManager.getInstance(requireContext());
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_add_playlist, container, false);
}

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);

tabLayout = view.findViewById(R.id.tab_layout);
viewPager = view.findViewById(R.id.view_pager);

setupViewPager();
}

/**
* Configura o ViewPager com os fragmentos de entrada M3U e Xtream Codes
*/
private void setupViewPager() {
tabAdapter = new PlaylistTabAdapter(this);
viewPager.setAdapter(tabAdapter);

// Conecta o TabLayout com o ViewPager2
new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
if (position == 0) {
tab.setText(R.string.m3u_url);
} else {
tab.setText(R.string.xtream_codes);
}
}).attach();
}

@Override
public void onM3UPlaylistAdd(String name, String url) {
playlistManager.addM3UPlaylist(name, url, new PlaylistManager.PlaylistLoadListener() {
@Override
public void onPlaylistLoaded(Playlist playlist) {
requireActivity().runOnUiThread(() -> {
Toast.makeText(requireContext(), R.string.playlist_added, Toast.LENGTH_SHORT).show();
// Volta para a lista de canais
requireActivity().getSupportFragmentManager().popBackStack();
});
}

@Override
public void onPlaylistLoadFailed(Exception e) {
requireActivity().runOnUiThread(() -> {
Toast.makeText(requireContext(), R.string.error_loading, Toast.LENGTH_SHORT).show();
});
}
});
}

@Override
public void onXtreamPlaylistAdd(String name, String url, String username, String password) {
playlistManager.addXtreamCodesPlaylist(name, url, username, password, new PlaylistManager.PlaylistLoadListener() {
@Override
public void onPlaylistLoaded(Playlist playlist) {
requireActivity().runOnUiThread(() -> {
Toast.makeText(requireContext(), R.string.playlist_added, Toast.LENGTH_SHORT).show();
// Volta para a lista de canais
requireActivity().getSupportFragmentManager().popBackStack();
});
}

@Override
public void onPlaylistLoadFailed(Exception e) {
requireActivity().runOnUiThread(() -> {
Toast.makeText(requireContext(), R.string.error_loading, Toast.LENGTH_SHORT).show();
});
}
});
}
}
31 changes: 31 additions & 0 deletions AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.pitv.player">

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true">

<activity
android:name=".MainActivity"
android:exported="true"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

</application>

</manifest>
92 changes: 92 additions & 0 deletions Channel.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package com.pitv.player.model;

import java.io.Serializable;

/**
* Classe que representa um canal de IPTV
*/
public class Channel implements Serializable {
private String id;
private String name;
private String url;
private String logoUrl;
private String group;
private boolean isFavorite;

public Channel() {
// Construtor vazio necessário para algumas operações
}

public Channel(String id, String name, String url, String logoUrl, String group) {
this.id = id;
this.name = name;
this.url = url;
this.logoUrl = logoUrl;
this.group = group;
this.isFavorite = false;
}

// Getters e Setters
public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getUrl() {
return url;
}

public void setUrl(String url) {
this.url = url;
}

public String getLogoUrl() {
return logoUrl;
}

public void setLogoUrl(String logoUrl) {
this.logoUrl = logoUrl;
}

public String getGroup() {
return group;
}

public void setGroup(String group) {
this.group = group;
}

public boolean isFavorite() {
return isFavorite;
}

public void setFavorite(boolean favorite) {
isFavorite = favorite;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

Channel channel = (Channel) o;

return id != null ? id.equals(channel.id) : channel.id == null;
}

@Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
}
}
125 changes: 125 additions & 0 deletions ChannelAdapter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package com.pitv.player.adapter;

import android.content.Context;
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 com.bumptech.glide.Glide;
import com.pitv.player.R;
import com.pitv.player.model.Channel;
import com.pitv.player.service.PlaylistManager;

import java.util.List;

/**
* Adapter para exibição de canais em um RecyclerView
*/
public class ChannelAdapter extends RecyclerView.Adapter<ChannelAdapter.ChannelViewHolder> {

private final Context context;
private final List<Channel> channels;
private final OnChannelClickListener listener;
private final PlaylistManager playlistManager;

public interface OnChannelClickListener {
void onChannelClick(Channel channel);
}

public ChannelAdapter(Context context, List<Channel> channels, OnChannelClickListener listener) {
this.context = context;
this.channels = channels;
this.listener = listener;
this.playlistManager = PlaylistManager.getInstance(context);
}

@NonNull
@Override
public ChannelViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.item_channel, parent, false);
return new ChannelViewHolder(view);
}

@Override
public void onBindViewHolder(@NonNull ChannelViewHolder holder, int position) {
Channel channel = channels.get(position);
holder.bind(channel);
}

@Override
public int getItemCount() {
return channels.size();
}

class ChannelViewHolder extends RecyclerView.ViewHolder {
private final ImageView logoImageView;
private final TextView nameTextView;
private final TextView groupTextView;
private final ImageView favoriteImageView;

public ChannelViewHolder(@NonNull View itemView) {
super(itemView);
logoImageView = itemView.findViewById(R.id.channel_logo);
nameTextView = itemView.findViewById(R.id.channel_name);
groupTextView = itemView.findViewById(R.id.channel_group);
favoriteImageView = itemView.findViewById(R.id.favorite_icon);

itemView.setOnClickListener(v -> {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION && listener != null) {
listener.onChannelClick(channels.get(position));
}
});

favoriteImageView.setOnClickListener(v -> {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
Channel channel = channels.get(position);
toggleFavorite(channel);
notifyItemChanged(position);
}
});
}

public void bind(Channel channel) {
nameTextView.setText(channel.getName());
groupTextView.setText(channel.getGroup());

// Carrega o logo do canal
if (channel.getLogoUrl() != null && !channel.getLogoUrl().isEmpty()) {
Glide.with(context)
.load(channel.getLogoUrl())
.placeholder(R.drawable.default_channel_logo)
.error(R.drawable.default_channel_logo)
.into(logoImageView);
} else {
logoImageView.setImageResource(R.drawable.default_channel_logo);
}

// Atualiza o ícone de favorito
updateFavoriteIcon(channel);
}

private void updateFavoriteIcon(Channel channel) {
if (playlistManager.isFavorite(channel)) {
favoriteImageView.setImageResource(R.drawable.ic_favorite);
} else {
favoriteImageView.setImageResource(R.drawable.ic_favorite_border);
}
}

private void toggleFavorite(Channel channel) {
if (playlistManager.isFavorite(channel)) {
playlistManager.removeFromFavorites(channel);
} else {
playlistManager.addToFavorites(channel);
}
updateFavoriteIcon(channel);
}
}
}
Loading