diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 32df2367fd107322107696e480db1fb3cce910be..d6b9d66cc46b3f135d792a1a422712dcf38a3c04 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -53,6 +53,12 @@ android:launchMode="singleTask" android:theme="@style/AppTheme.Light" /> + <activity + android:name=".ui.chat.ChannelDetailActivity" + android:label="Channel Detail" + android:launchMode="singleTask" + android:theme="@style/SetupTheme" /> + <activity android:name=".ui.setup.AccountSetupActivity" android:label="Setup a new Account" diff --git a/app/src/main/java/de/kuschku/libquassel/client/BufferManager.java b/app/src/main/java/de/kuschku/libquassel/client/BufferManager.java index 328dc8531c8370a4f3d544611f19ab8f1bcdd608..a7a4ea461ceba5d7ee895c701da4f7f141c50bbc 100644 --- a/app/src/main/java/de/kuschku/libquassel/client/BufferManager.java +++ b/app/src/main/java/de/kuschku/libquassel/client/BufferManager.java @@ -25,8 +25,6 @@ import android.support.annotation.IntRange; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import com.google.common.collect.Sets; - import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -176,6 +174,7 @@ public class BufferManager { laterRequests.clear(); int waitingMax = client.backlogManager().waitingMax(); int waitingCurrently = client.backlogManager().waiting().size(); + client.provider().sendEvent(new BacklogInitEvent(waitingMax - waitingCurrently, waitingMax)); } } diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/Network.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/Network.java index a26880d34ddb2575fd390984483de2e9bf44c5ee..c5b6055f46f350b7a0950c71a6169603cabed94e 100644 --- a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/Network.java +++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/Network.java @@ -45,6 +45,8 @@ import de.kuschku.util.CompatibilityUtils; import de.kuschku.util.irc.IrcCaseMapper; import de.kuschku.util.irc.IrcUserUtils; import de.kuschku.util.irc.ModeUtils; +import de.kuschku.util.irc.chanmodes.IrcModeProvider; +import de.kuschku.util.irc.chanmodes.IrcModeProviderFactory; public class Network extends ANetwork<Network> implements Observer { private final Map<String, QIrcChannel> channels; @@ -66,6 +68,7 @@ public class Network extends ANetwork<Network> implements Observer { private List<String> prefixes; private List<String> prefixModes; + private IrcModeProvider modeProvider; public Network(Map<String, QIrcChannel> channels, Map<String, QIrcUser> nicks, @@ -337,6 +340,13 @@ public class Network extends ANetwork<Network> implements Observer { return prefixModes; } + @Override + public IrcModeProvider modeProvider() { + if (modeProvider == null) + modeProvider = IrcModeProviderFactory.identifyServer(supports.get("CHANMODES")); + return modeProvider; + } + @Override public void determinePrefixes() { // seems like we have to construct them first diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QNetwork.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QNetwork.java index c7f42451de13d909911ac209fdcddac6afd1a0b8..84a36d0002e66d552612562b2a0ca95f4ba5f052 100644 --- a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QNetwork.java +++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QNetwork.java @@ -30,6 +30,7 @@ import de.kuschku.libquassel.objects.types.NetworkServer; import de.kuschku.libquassel.syncables.Synced; import de.kuschku.libquassel.syncables.types.impl.IrcChannel; import de.kuschku.libquassel.syncables.types.impl.NetworkInfo; +import de.kuschku.util.irc.chanmodes.IrcModeProvider; public interface QNetwork extends QObservable { int networkId(); @@ -115,6 +116,8 @@ public interface QNetwork extends QObservable { List<String> prefixModes(); + IrcModeProvider modeProvider(); + void determinePrefixes(); boolean supports(final String param); diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChannelDetailActivity.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChannelDetailActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..370b97f21b73ae31c1ab567d4ec0b5e97fb233d7 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChannelDetailActivity.java @@ -0,0 +1,160 @@ +/* + * QuasselDroid - Quassel client for Android + * Copyright (C) 2016 Janne Koschinski + * Copyright (C) 2016 Ken Børge Viktil + * Copyright (C) 2016 Magnus Fjell + * Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org> + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package de.kuschku.quasseldroid_ng.ui.chat; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.Toolbar; +import android.text.method.LinkMovementMethod; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import butterknife.Bind; +import butterknife.ButterKnife; +import de.kuschku.libquassel.events.GeneralErrorEvent; +import de.kuschku.libquassel.localtypes.buffers.ChannelBuffer; +import de.kuschku.libquassel.syncables.types.interfaces.QIrcChannel; +import de.kuschku.quasseldroid_ng.R; +import de.kuschku.quasseldroid_ng.service.ClientBackgroundThread; +import de.kuschku.util.irc.chanmodes.ChanMode; +import de.kuschku.util.irc.chanmodes.IrcModeProvider; +import de.kuschku.util.irc.format.IrcFormatHelper; +import de.kuschku.util.servicebound.BoundActivity; + +public class ChannelDetailActivity extends BoundActivity { + @Bind(R.id.topic) + TextView topic; + @Bind(R.id.mode) + TextView mode; + @Bind(R.id.modes) + LinearLayout modes; + @Bind(R.id.toolbar) + Toolbar toolbar; + ModeAdapter modeAdapter; + private int buffer; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + buffer = getIntent().getIntExtra("buffer", -1); + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_channel_detail); + ButterKnife.bind(this); + } + + @Override + protected void onConnectToThread(@Nullable ClientBackgroundThread thread) { + super.onConnectToThread(thread); + + ChannelBuffer buffer = (ChannelBuffer) context.client().bufferManager().buffer(this.buffer); + QIrcChannel channel = buffer.getChannel(); + String modeString = channel.channelModeString(); + + topic.setText(new IrcFormatHelper(context).formatIrcMessage(context.client(), channel.topic(), buffer.getInfo(), v -> finish())); + topic.setMovementMethod(LinkMovementMethod.getInstance()); + mode.setText(String.format("Channel Mode %s", modeString)); + + if (getResources().getBoolean(R.bool.isTablet)) { + findViewById(R.id.appBar).setPadding(0, 0, 0, 0); + } else { + findViewById(R.id.appBar).setPadding(0, (int) getResources().getDimension(R.dimen.materialize_statusbar), 0, 0); + } + + toolbar.setTitle(channel.name()); + setSupportActionBar(toolbar); + + modes.removeAllViews(); + IrcModeProvider provider = channel.network().modeProvider(); + for (char c : modeString.toCharArray()) { + ChanMode mode = provider.modeFromChar(c); + if (mode != null) { + View v = getLayoutInflater().inflate(R.layout.widget_channel_mode, modes, false); + TextView name = (TextView) v.findViewById(R.id.name); + TextView description = (TextView) v.findViewById(R.id.description); + + String modeName = context.themeUtil().translations.chanModeToName(mode); + name.setText(String.format("%s (+%s)", modeName, c)); + String modeDescription = context.themeUtil().translations.chanModeToDescription(mode); + description.setText(modeDescription); + modes.addView(v); + } + } + } + + public void onEventMainThread(GeneralErrorEvent event) { + Log.e("DEBUG", String.valueOf(event)); + } + + public class ModeAdapter extends RecyclerView.Adapter<ChannelDetailActivity.ModeViewHolder> { + private List<ChanMode> channelModes = new ArrayList<>(); + + public void setModes(Collection<ChanMode> chanModes) { + channelModes.clear(); + channelModes.addAll(chanModes); + Log.e("DEBUG", String.valueOf(channelModes)); + notifyDataSetChanged(); + } + + @Override + public ChannelDetailActivity.ModeViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + LayoutInflater inflater = LayoutInflater.from(parent.getContext()); + return new ModeViewHolder(inflater.inflate(R.layout.widget_channel_mode, parent, false)); + } + + @Override + public void onBindViewHolder(ChannelDetailActivity.ModeViewHolder holder, int position) { + holder.bind(channelModes.get(position)); + } + + @Override + public int getItemCount() { + return channelModes.size(); + } + } + + public class ModeViewHolder extends RecyclerView.ViewHolder { + + @Bind(R.id.name) + TextView name; + + @Bind(R.id.description) + TextView description; + + public ModeViewHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + + public void bind(ChanMode mode) { + name.setText(context.themeUtil().translations.chanModeToName(mode)); + description.setText(context.themeUtil().translations.chanModeToDescription(mode)); + } + } +} diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MainActivity.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MainActivity.java index db96d8511d2a5f66fdea7f54a08a92d03fd9bf5f..b7dd691323ccb00fc008c58cd38db4eaac433404 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MainActivity.java +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MainActivity.java @@ -21,6 +21,7 @@ package de.kuschku.quasseldroid_ng.ui.chat; +import android.content.Intent; import android.os.Bundle; import android.support.annotation.IntRange; import android.support.annotation.NonNull; @@ -128,6 +129,13 @@ public class MainActivity extends BoundActivity { setContentView(R.layout.activity_main); ButterKnife.bind(this); toolbarWrapper = new ToolbarWrapper(toolbar); + toolbarWrapper.setOnClickListener(v -> { + if (context.client() != null) { + Intent intent = new Intent(this, ChannelDetailActivity.class); + intent.putExtra("buffer", context.client().backlogManager().open()); + startActivity(intent); + } + }); setSupportActionBar(toolbar); layoutHelper = ActivityImplFactory.of(getResources().getBoolean(R.bool.isTablet), this); accountHeader = buildAccountHeader(); @@ -274,7 +282,7 @@ public class MainActivity extends BoundActivity { if (channel == null) { toolbarWrapper.setSubtitle(null); } else { - toolbarWrapper.setSubtitle(channel.topic()); + toolbarWrapper.setSubtitle(context.deserializer().formatString(channel.topic())); } } else { toolbarWrapper.setSubtitle(null); diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/theme/ThemeUtil.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/theme/ThemeUtil.java index b2f73236c1bc619055cba87546fe84006566a268..cb41cd1046561a35dbff2547d0c2721aaef27114 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/theme/ThemeUtil.java +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/theme/ThemeUtil.java @@ -34,6 +34,7 @@ import de.kuschku.util.annotationbind.AutoBinder; import de.kuschku.util.annotationbind.AutoColor; import de.kuschku.util.annotationbind.AutoDimen; import de.kuschku.util.annotationbind.AutoString; +import de.kuschku.util.irc.chanmodes.ChanMode; import de.kuschku.util.ui.DateTimeFormatHelper; import de.kuschku.util.ui.SpanFormatter; @@ -154,6 +155,236 @@ public class ThemeUtil { @AutoString(R.string.statusWelcome) public String statusWelcome; + + @AutoString(R.string.chanMode_RESTRICT_TOPIC_NAME) + public String chanMode_RESTRICT_TOPIC_NAME; + + @AutoString(R.string.chanMode_RESTRICT_TOPIC_DESCRIPTION) + public String chanMode_RESTRICT_TOPIC_DESCRIPTION; + + @AutoString(R.string.chanMode_BLOCK_COLORS_NAME) + public String chanMode_BLOCK_COLOR_NAME; + + @AutoString(R.string.chanMode_BLOCK_COLORS_DESCRIPTION) + public String chanMode_BLOCK_COLOR_DESCRIPTION; + + @AutoString(R.string.chanMode_STRIP_COLORS_NAME) + public String chanMode_STRIP_COLOR_NAME; + + @AutoString(R.string.chanMode_STRIP_COLORS_DESCRIPTION) + public String chanMode_STRIP_COLOR_DESCRIPTION; + + @AutoString(R.string.chanMode_ONLY_INVITE_NAME) + public String chanMode_ONLY_INVITE_NAME; + + @AutoString(R.string.chanMode_ONLY_INVITE_DESCRIPTION) + public String chanMode_ONLY_INVITE_DESCRIPTION; + + @AutoString(R.string.chanMode_ONLY_SSL_NAME) + public String chanMode_ONLY_SSL_NAME; + + @AutoString(R.string.chanMode_ONLY_SSL_DESCRIPTION) + public String chanMode_ONLY_SSL_DESCRIPTION; + + @AutoString(R.string.chanMode_UNLISTED_NAME) + public String chanMode_UNLISTED_NAME; + + @AutoString(R.string.chanMode_UNLISTED_DESCRIPTION) + public String chanMode_UNLISTED_DESCRIPTION; + + @AutoString(R.string.chanMode_BLOCK_UNIDENTIFIED_NAME) + public String chanMode_BLOCK_UNIDENTIFIED_NAME; + + @AutoString(R.string.chanMode_BLOCK_UNIDENTIFIED_DESCRIPTION) + public String chanMode_BLOCK_UNIDENTIFIED_DESCRIPTION; + + @AutoString(R.string.chanMode_PARANOID_NAME) + public String chanMode_PARANOID_NAME; + + @AutoString(R.string.chanMode_PARANOID_DESCRIPTION) + public String chanMode_PARANOID_DESCRIPTION; + + @AutoString(R.string.chanMode_REGISTERED_NAME) + public String chanMode_REGISTERED_NAME; + + @AutoString(R.string.chanMode_REGISTERED_DESCRIPTION) + public String chanMode_REGISTERED_DESCRIPTION; + + @AutoString(R.string.chanMode_MODERATED_NAME) + public String chanMode_MODERATED_NAME; + + @AutoString(R.string.chanMode_MODERATED_DESCRIPTION) + public String chanMode_MODERATED_DESCRIPTION; + + @AutoString(R.string.chanMode_BLOCK_EXTERNAL_NAME) + public String chanMode_BLOCK_EXTERNAL_NAME; + + @AutoString(R.string.chanMode_BLOCK_EXTERNAL_DESCRIPTION) + public String chanMode_BLOCK_EXTERNAL_DESCRIPTION; + + @AutoString(R.string.chanMode_ANTIFLOOD_NAME) + public String chanMode_ANTIFLOOD_NAME; + + @AutoString(R.string.chanMode_ANTIFLOOD_DESCRIPTION) + public String chanMode_ANTIFLOOD_DESCRIPTION; + + @AutoString(R.string.chanMode_PASSWORD_NAME) + public String chanMode_PASSWORD_NAME; + + @AutoString(R.string.chanMode_PASSWORD_DESCRIPTION) + public String chanMode_PASSWORD_DESCRIPTION; + + @AutoString(R.string.chanMode_LIMIT_NAME) + public String chanMode_LIMIT_NAME; + + @AutoString(R.string.chanMode_LIMIT_DESCRIPTION) + public String chanMode_LIMIT_DESCRIPTION; + + @AutoString(R.string.chanMode_REDUCED_MODERATION_NAME) + public String chanMode_REDUCED_MODERATION_NAME; + + @AutoString(R.string.chanMode_REDUCED_MODERATION_DESCRIPTION) + public String chanMode_REDUCED_MODERATION_DESCRIPTION; + + @AutoString(R.string.chanMode_BLOCK_NOTICE_NAME) + public String chanMode_BLOCK_NOTICE_NAME; + + @AutoString(R.string.chanMode_BLOCK_NOTICE_DESCRIPTION) + public String chanMode_BLOCK_NOTICE_DESCRIPTION; + + @AutoString(R.string.chanMode_DISABLE_INVITE_NAME) + public String chanMode_DISABLE_INVITE_NAME; + + @AutoString(R.string.chanMode_DISABLE_INVITE_DESCRIPTION) + public String chanMode_DISABLE_INVITE_DESCRIPTION; + + @AutoString(R.string.chanMode_AUDITORIUM_NAME) + public String chanMode_AUDITORIUM_NAME; + + @AutoString(R.string.chanMode_AUDITORIUM_DESCRIPTION) + public String chanMode_AUDITORIUM_DESCRIPTION; + + @AutoString(R.string.chanMode_QUIET_UNIDENTIFIED_NAME) + public String chanMode_QUIET_UNIDENTIFIED_NAME; + + @AutoString(R.string.chanMode_QUIET_UNIDENTIFIED_DESCRIPTION) + public String chanMode_QUIET_UNIDENTIFIED_DESCRIPTION; + + @AutoString(R.string.chanMode_BLOCK_KICK_NAME) + public String chanMode_BLOCK_KICK_NAME; + + @AutoString(R.string.chanMode_BLOCK_KICK_DESCRIPTION) + public String chanMode_BLOCK_KICK_DESCRIPTION; + + @AutoString(R.string.chanMode_PERMANENT_NAME) + public String chanMode_PERMANENT_NAME; + + @AutoString(R.string.chanMode_PERMANENT_DESCRIPTION) + public String chanMode_PERMANENT_DESCRIPTION; + + @AutoString(R.string.chanMode_ONLY_OPER_NAME) + public String chanMode_ONLY_OPER_NAME; + + @AutoString(R.string.chanMode_ONLY_OPER_DESCRIPTION) + public String chanMode_ONLY_OPER_DESCRIPTION; + + @AutoString(R.string.chanMode_ONLY_HELPOPER_NAME) + public String chanMode_ONLY_HELPOPER_NAME; + + @AutoString(R.string.chanMode_ONLY_HELPOPER_DESCRIPTION) + public String chanMode_ONLY_HELPOPER_DESCRIPTION; + + @AutoString(R.string.chanMode_BLOCK_NICKCHANGE_NAME) + public String chanMode_BLOCK_NICKCHANGE_NAME; + + @AutoString(R.string.chanMode_BLOCK_NICKCHANGE_DESCRIPTION) + public String chanMode_BLOCK_NICKCHANGE_DESCRIPTION; + + @AutoString(R.string.chanMode_JOIN_THROTTLE_NAME) + public String chanMode_JOIN_THROTTLE_NAME; + + @AutoString(R.string.chanMode_JOIN_THROTTLE_DESCRIPTION) + public String chanMode_JOIN_THROTTLE_DESCRIPTION; + + @AutoString(R.string.chanMode_ALLOW_INVITE_NAME) + public String chanMode_ALLOW_INVITE_NAME; + + @AutoString(R.string.chanMode_ALLOW_INVITE_DESCRIPTION) + public String chanMode_ALLOW_INVITE_DESCRIPTION; + + @AutoString(R.string.chanMode_BLOCK_FORWARDING_NAME) + public String chanMode_BLOCK_FORWARDING_NAME; + + @AutoString(R.string.chanMode_BLOCK_FORWARDING_DESCRIPTION) + public String chanMode_BLOCK_FORWARDING_DESCRIPTION; + + @AutoString(R.string.chanMode_ALLOW_FORWARD_NAME) + public String chanMode_ALLOW_FORWARD_NAME; + + @AutoString(R.string.chanMode_ALLOW_FORWARD_DESCRIPTION) + public String chanMode_ALLOW_FORWARD_DESCRIPTION; + + @AutoString(R.string.chanMode_BLOCK_ACTION_NAME) + public String chanMode_BLOCK_ACTION_NAME; + + @AutoString(R.string.chanMode_BLOCK_ACTION_DESCRIPTION) + public String chanMode_BLOCK_ACTION_DESCRIPTION; + + @AutoString(R.string.chanMode_BLOCK_CAPS_NAME) + public String chanMode_BLOCK_CAPS_NAME; + + @AutoString(R.string.chanMode_BLOCK_CAPS_DESCRIPTION) + public String chanMode_BLOCK_CAPS_DESCRIPTION; + + @AutoString(R.string.chanMode_BLOCK_KNOCK_NAME) + public String chanMode_BLOCK_KNOCK_NAME; + + @AutoString(R.string.chanMode_BLOCK_KNOCK_DESCRIPTION) + public String chanMode_BLOCK_KNOCK_DESCRIPTION; + + @AutoString(R.string.chanMode_CENSOR_NAME) + public String chanMode_CENSOR_NAME; + + @AutoString(R.string.chanMode_CENSOR_DESCRIPTION) + public String chanMode_CENSOR_DESCRIPTION; + + @AutoString(R.string.chanMode_HIDE_JOINS_NAME) + public String chanMode_HIDE_JOINS_NAME; + + @AutoString(R.string.chanMode_HIDE_JOINS_DESCRIPTION) + public String chanMode_HIDE_JOINS_DESCRIPTION; + + @AutoString(R.string.chanMode_BLOCK_REPEAT_NAME) + public String chanMode_BLOCK_REPEAT_NAME; + + @AutoString(R.string.chanMode_BLOCK_REPEAT_DESCRIPTION) + public String chanMode_BLOCK_REPEAT_DESCRIPTION; + + @AutoString(R.string.chanMode_BLOCK_AUTOREJOIN_NAME) + public String chanMode_BLOCK_AUTOREJOIN_NAME; + + @AutoString(R.string.chanMode_BLOCK_AUTOREJOIN_DESCRIPTION) + public String chanMode_BLOCK_AUTOREJOIN_DESCRIPTION; + + @AutoString(R.string.chanMode_IS_SECURE_NAME) + public String chanMode_IS_SECURE_NAME; + + @AutoString(R.string.chanMode_IS_SECURE_DESCRIPTION) + public String chanMode_IS_SECURE_DESCRIPTION; + + @AutoString(R.string.chanMode_BLOCK_CTCP_NAME) + public String chanMode_BLOCK_CTCP_NAME; + + @AutoString(R.string.chanMode_BLOCK_CTCP_DESCRIPTION) + public String chanMode_BLOCK_CTCP_DESCRIPTION; + + @AutoString(R.string.chanMode_ONLY_ADMIN_NAME) + public String chanMode_ONLY_ADMIN_NAME; + + @AutoString(R.string.chanMode_ONLY_ADMIN_DESCRIPTION) + public String chanMode_ONLY_ADMIN_DESCRIPTION; + + @NonNull public CharSequence formatUsername(@NonNull CharSequence nick, @NonNull CharSequence hostmask) { return SpanFormatter.format(usernameHostmask, nick, hostmask); @@ -236,6 +467,174 @@ public class ThemeUtil { public CharSequence formatPlain(@NonNull CharSequence nick, @NonNull CharSequence message) { return SpanFormatter.format(messagePlain, nick, message); } + + public String chanModeToDescription(ChanMode mode) { + switch (mode) { + case RESTRICT_TOPIC: + return chanMode_RESTRICT_TOPIC_DESCRIPTION; + case BLOCK_CTCP: + return chanMode_BLOCK_CTCP_DESCRIPTION; + case BLOCK_COLOR: + return chanMode_BLOCK_COLOR_DESCRIPTION; + case STRIP_COLOR: + return chanMode_STRIP_COLOR_DESCRIPTION; + case ONLY_INVITE: + return chanMode_ONLY_INVITE_DESCRIPTION; + case ONLY_ADMIN: + return chanMode_ONLY_ADMIN_DESCRIPTION; + case ONLY_SSL: + return chanMode_ONLY_SSL_DESCRIPTION; + case UNLISTED: + return chanMode_UNLISTED_DESCRIPTION; + case BLOCK_UNIDENTIFIED: + return chanMode_BLOCK_UNIDENTIFIED_DESCRIPTION; + case PARANOID: + return chanMode_PARANOID_DESCRIPTION; + case REGISTERED: + return chanMode_REGISTERED_DESCRIPTION; + case MODERATED: + return chanMode_MODERATED_DESCRIPTION; + case BLOCK_EXTERNAL: + return chanMode_BLOCK_EXTERNAL_DESCRIPTION; + case ANTIFLOOD: + return chanMode_ANTIFLOOD_DESCRIPTION; + case PASSWORD: + return chanMode_PASSWORD_DESCRIPTION; + case LIMIT: + return chanMode_LIMIT_DESCRIPTION; + case REDUCED_MODERATION: + return chanMode_REDUCED_MODERATION_DESCRIPTION; + case BLOCK_NOTICE: + return chanMode_BLOCK_NOTICE_DESCRIPTION; + case DISABLE_INVITE: + return chanMode_DISABLE_INVITE_DESCRIPTION; + case AUDITORIUM: + return chanMode_AUDITORIUM_DESCRIPTION; + case QUIET_UNIDENTIFIED: + return chanMode_QUIET_UNIDENTIFIED_DESCRIPTION; + case BLOCK_KICK: + return chanMode_BLOCK_KICK_DESCRIPTION; + case PERMANENT: + return chanMode_PERMANENT_DESCRIPTION; + case ONLY_OPER: + return chanMode_ONLY_OPER_DESCRIPTION; + case ONLY_HELPOPER: + return chanMode_ONLY_HELPOPER_DESCRIPTION; + case BLOCK_NICKCHANGE: + return chanMode_BLOCK_NICKCHANGE_DESCRIPTION; + case JOIN_THROTTLE: + return chanMode_JOIN_THROTTLE_DESCRIPTION; + case ALLOW_INVITE: + return chanMode_ALLOW_INVITE_DESCRIPTION; + case BLOCK_FORWARDING: + return chanMode_BLOCK_FORWARDING_DESCRIPTION; + case ALLOW_FORWARD: + return chanMode_ALLOW_FORWARD_DESCRIPTION; + case BLOCK_ACTION: + return chanMode_BLOCK_ACTION_DESCRIPTION; + case BLOCK_CAPS: + return chanMode_BLOCK_CAPS_DESCRIPTION; + case BLOCK_KNOCK: + return chanMode_BLOCK_KNOCK_DESCRIPTION; + case CENSOR: + return chanMode_CENSOR_DESCRIPTION; + case HIDE_JOINS: + return chanMode_HIDE_JOINS_DESCRIPTION; + case BLOCK_REPEAT: + return chanMode_BLOCK_REPEAT_DESCRIPTION; + case BLOCK_AUTOREJOIN: + return chanMode_BLOCK_AUTOREJOIN_DESCRIPTION; + case IS_SECURE: + return chanMode_IS_SECURE_DESCRIPTION; + case FORWARD: + break; + } + return null; + } + + public String chanModeToName(ChanMode mode) { + switch (mode) { + case RESTRICT_TOPIC: + return chanMode_RESTRICT_TOPIC_NAME; + case BLOCK_CTCP: + return chanMode_BLOCK_CTCP_NAME; + case BLOCK_COLOR: + return chanMode_BLOCK_COLOR_NAME; + case STRIP_COLOR: + return chanMode_STRIP_COLOR_NAME; + case ONLY_INVITE: + return chanMode_ONLY_INVITE_NAME; + case ONLY_ADMIN: + return chanMode_ONLY_ADMIN_NAME; + case ONLY_SSL: + return chanMode_ONLY_SSL_NAME; + case UNLISTED: + return chanMode_UNLISTED_NAME; + case BLOCK_UNIDENTIFIED: + return chanMode_BLOCK_UNIDENTIFIED_NAME; + case PARANOID: + return chanMode_PARANOID_NAME; + case REGISTERED: + return chanMode_REGISTERED_NAME; + case MODERATED: + return chanMode_MODERATED_NAME; + case BLOCK_EXTERNAL: + return chanMode_BLOCK_EXTERNAL_NAME; + case ANTIFLOOD: + return chanMode_ANTIFLOOD_NAME; + case PASSWORD: + return chanMode_PASSWORD_NAME; + case LIMIT: + return chanMode_LIMIT_NAME; + case REDUCED_MODERATION: + return chanMode_REDUCED_MODERATION_NAME; + case BLOCK_NOTICE: + return chanMode_BLOCK_NOTICE_NAME; + case DISABLE_INVITE: + return chanMode_DISABLE_INVITE_NAME; + case AUDITORIUM: + return chanMode_AUDITORIUM_NAME; + case QUIET_UNIDENTIFIED: + return chanMode_QUIET_UNIDENTIFIED_NAME; + case BLOCK_KICK: + return chanMode_BLOCK_KICK_NAME; + case PERMANENT: + return chanMode_PERMANENT_NAME; + case ONLY_OPER: + return chanMode_ONLY_OPER_NAME; + case ONLY_HELPOPER: + return chanMode_ONLY_HELPOPER_NAME; + case BLOCK_NICKCHANGE: + return chanMode_BLOCK_NICKCHANGE_NAME; + case JOIN_THROTTLE: + return chanMode_JOIN_THROTTLE_NAME; + case ALLOW_INVITE: + return chanMode_ALLOW_INVITE_NAME; + case BLOCK_FORWARDING: + return chanMode_BLOCK_FORWARDING_NAME; + case ALLOW_FORWARD: + return chanMode_ALLOW_FORWARD_NAME; + case BLOCK_ACTION: + return chanMode_BLOCK_ACTION_NAME; + case BLOCK_CAPS: + return chanMode_BLOCK_CAPS_NAME; + case BLOCK_KNOCK: + return chanMode_BLOCK_KNOCK_NAME; + case CENSOR: + return chanMode_CENSOR_NAME; + case HIDE_JOINS: + return chanMode_HIDE_JOINS_NAME; + case BLOCK_REPEAT: + return chanMode_BLOCK_REPEAT_NAME; + case BLOCK_AUTOREJOIN: + return chanMode_BLOCK_AUTOREJOIN_NAME; + case IS_SECURE: + return chanMode_IS_SECURE_NAME; + case FORWARD: + break; + } + return null; + } } public static class Colors { diff --git a/app/src/main/java/de/kuschku/util/irc/format/IrcFormatDeserializer.java b/app/src/main/java/de/kuschku/util/irc/format/IrcFormatDeserializer.java index eeb00f40bf790e1046db09889f7e97c027e9420b..68a11672bf3a6a2c956e04b491738b8c4f30f5a9 100644 --- a/app/src/main/java/de/kuschku/util/irc/format/IrcFormatDeserializer.java +++ b/app/src/main/java/de/kuschku/util/irc/format/IrcFormatDeserializer.java @@ -110,8 +110,10 @@ public class IrcFormatDeserializer { * @param str mIRC formatted String * @return a CharSequence with Android’s span format representing the input string */ - @NonNull - public CharSequence formatString(@NonNull String str) { + @Nullable + public CharSequence formatString(@Nullable String str) { + if (str == null) return null; + SpannableStringBuilder plainText = new SpannableStringBuilder(); FormatDescription bold = null; FormatDescription italic = null; diff --git a/app/src/main/java/de/kuschku/util/irc/format/IrcFormatHelper.java b/app/src/main/java/de/kuschku/util/irc/format/IrcFormatHelper.java index ad2ecb6ef39d10779d8f70e9bf8dc3bd03659284..185216fafebbb6cfae951fd302e3db93cdfb1bbe 100644 --- a/app/src/main/java/de/kuschku/util/irc/format/IrcFormatHelper.java +++ b/app/src/main/java/de/kuschku/util/irc/format/IrcFormatHelper.java @@ -45,6 +45,7 @@ import java.util.regex.Pattern; import de.kuschku.libquassel.client.Client; import de.kuschku.libquassel.localtypes.buffers.Buffer; import de.kuschku.libquassel.message.Message; +import de.kuschku.libquassel.primitives.types.BufferInfo; import de.kuschku.libquassel.syncables.types.interfaces.QIrcChannel; import de.kuschku.quasseldroid_ng.ui.theme.AppContext; import de.kuschku.util.irc.IrcUserUtils; @@ -83,19 +84,24 @@ public class IrcFormatHelper { @NonNull public CharSequence formatIrcMessage(@NonNull Client client, @NonNull Message message) { + return formatIrcMessage(client, message.content, message.bufferInfo, null); + } + + @NonNull + public CharSequence formatIrcMessage(@NonNull Client client, @NonNull String text, BufferInfo bufferInfo, View.OnClickListener listener) { List<FutureClickableSpan> spans = new LinkedList<>(); - SpannableString str = new SpannableString(context.deserializer().formatString(message.content)); + SpannableString str = new SpannableString(context.deserializer().formatString(text)); Matcher urlMatcher = urlPattern.matcher(str); while (urlMatcher.find()) { spans.add(new FutureClickableSpan(new CustomURLSpan(urlMatcher.group()), urlMatcher.start(), urlMatcher.end())); } Matcher channelMatcher = channelPattern.matcher(str); while (channelMatcher.find()) { - QIrcChannel channel = client.networkManager().network(message.bufferInfo.networkId()).ircChannel(channelMatcher.group()); + QIrcChannel channel = client.networkManager().network(bufferInfo.networkId()).ircChannel(channelMatcher.group()); Buffer buffer = client.bufferManager().channel(channel); if (buffer != null) - spans.add(new FutureClickableSpan(new ChannelSpan(client, buffer.getInfo().id()), channelMatcher.start(), channelMatcher.end())); + spans.add(new FutureClickableSpan(new ChannelSpan(client, buffer.getInfo().id(), listener), channelMatcher.start(), channelMatcher.end())); } for (FutureClickableSpan span : spans) { str.setSpan(span.span, span.start, span.end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); @@ -141,15 +147,19 @@ public class IrcFormatHelper { @NonNull private final Client client; private final int bufferid; + private final View.OnClickListener listener; - public ChannelSpan(@NonNull Client client, int bufferid) { + public ChannelSpan(@NonNull Client client, int bufferid, View.OnClickListener listener) { this.client = client; this.bufferid = bufferid; + this.listener = listener; } @Override public void onClick(View widget) { client.backlogManager().open(bufferid); + if (listener != null) + listener.onClick(widget); } } } diff --git a/app/src/main/res/layout/activity_channel_detail.xml b/app/src/main/res/layout/activity_channel_detail.xml new file mode 100644 index 0000000000000000000000000000000000000000..7185ee79460cc58471197ce1800dd28cfa3896dd --- /dev/null +++ b/app/src/main/res/layout/activity_channel_detail.xml @@ -0,0 +1,109 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ QuasselDroid - Quassel client for Android + ~ Copyright (C) 2016 Janne Koschinski + ~ Copyright (C) 2016 Ken Børge Viktil + ~ Copyright (C) 2016 Magnus Fjell + ~ Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org> + ~ + ~ This program is free software: you can redistribute it and/or modify it + ~ under the terms of the GNU General Public License as published by the Free + ~ Software Foundation, either version 3 of the License, or (at your option) + ~ any later version. + ~ + ~ This program is distributed in the hope that it will be useful, + ~ but WITHOUT ANY WARRANTY; without even the implied warranty of + ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + ~ GNU General Public License for more details. + ~ + ~ You should have received a copy of the GNU General Public License along + ~ with this program. If not, see <http://www.gnu.org/licenses/>. + --> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="?attr/colorBackground" + android:orientation="vertical"> + + <android.support.design.widget.AppBarLayout + android:id="@+id/appBar" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <android.support.v7.widget.Toolbar + android:id="@+id/toolbar" + android:layout_width="match_parent" + android:layout_height="?attr/actionBarSize" /> + + </android.support.design.widget.AppBarLayout> + + <ScrollView + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:padding="4dp"> + + <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="4dp" + app:cardBackgroundColor="?attr/colorBackgroundCard" + app:cardUseCompatPadding="true" + app:contentPaddingBottom="24dp" + app:contentPaddingLeft="16dp" + app:contentPaddingRight="16dp" + app:contentPaddingTop="24dp"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Topic" + android:textAppearance="@style/Base.TextAppearance.AppCompat.Title" /> + + <Space + android:layout_width="match_parent" + android:layout_height="16dp" /> + + <TextView + android:id="@+id/topic" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="02-18 04:14:03.854 3960-3988/de.kuschku.quasseldroid_ng W/ResourceType: Failure getting entry for 0x0108035f (t=7 e=863) (error -75)" + android:textAppearance="@style/Base.TextAppearance.AppCompat.Subhead" /> + + </LinearLayout> + + </android.support.v7.widget.CardView> + + <TextView + android:id="@+id/mode" + style="@style/TextAppearance.AppCompat.Title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginBottom="8dp" + android:layout_marginLeft="8dp" + android:layout_marginRight="8dp" + android:layout_marginTop="16dp" /> + + <LinearLayout + android:id="@+id/modes" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" /> + + </LinearLayout> + + </ScrollView> + +</LinearLayout> diff --git a/app/src/main/res/layout/widget_channel_mode.xml b/app/src/main/res/layout/widget_channel_mode.xml new file mode 100644 index 0000000000000000000000000000000000000000..4ac0dd6baf23c7d56c27b9e52869416568e872ae --- /dev/null +++ b/app/src/main/res/layout/widget_channel_mode.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ QuasselDroid - Quassel client for Android + ~ Copyright (C) 2016 Janne Koschinski + ~ Copyright (C) 2016 Ken Børge Viktil + ~ Copyright (C) 2016 Magnus Fjell + ~ Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org> + ~ + ~ This program is free software: you can redistribute it and/or modify it + ~ under the terms of the GNU General Public License as published by the Free + ~ Software Foundation, either version 3 of the License, or (at your option) + ~ any later version. + ~ + ~ This program is distributed in the hope that it will be useful, + ~ but WITHOUT ANY WARRANTY; without even the implied warranty of + ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + ~ GNU General Public License for more details. + ~ + ~ You should have received a copy of the GNU General Public License along + ~ with this program. If not, see <http://www.gnu.org/licenses/>. + --> + +<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="4dp" + app:cardBackgroundColor="?attr/colorBackgroundCard" + app:cardUseCompatPadding="true" + app:contentPaddingBottom="16dp" + app:contentPaddingLeft="16dp" + app:contentPaddingRight="16dp" + app:contentPaddingTop="16dp"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <TextView + android:id="@+id/name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Invite Only (+i)" + android:textAppearance="@style/Base.TextAppearance.AppCompat.Title" /> + + <TextView + android:id="@+id/description" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Members must be invited to join this channel." + android:textAppearance="@style/Base.TextAppearance.AppCompat.Subhead" /> + + </LinearLayout> + +</android.support.v7.widget.CardView> diff --git a/app/src/main/res/values/strings_chanmodes.xml b/app/src/main/res/values/strings_chanmodes.xml new file mode 100644 index 0000000000000000000000000000000000000000..b55b8a2131a6bf18901a822fb48c83442ca2d969 --- /dev/null +++ b/app/src/main/res/values/strings_chanmodes.xml @@ -0,0 +1,137 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ QuasselDroid - Quassel client for Android + ~ Copyright (C) 2016 Janne Koschinski + ~ Copyright (C) 2016 Ken Børge Viktil + ~ Copyright (C) 2016 Magnus Fjell + ~ Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org> + ~ + ~ This program is free software: you can redistribute it and/or modify it + ~ under the terms of the GNU General Public License as published by the Free + ~ Software Foundation, either version 3 of the License, or (at your option) + ~ any later version. + ~ + ~ This program is distributed in the hope that it will be useful, + ~ but WITHOUT ANY WARRANTY; without even the implied warranty of + ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + ~ GNU General Public License for more details. + ~ + ~ You should have received a copy of the GNU General Public License along + ~ with this program. If not, see <http://www.gnu.org/licenses/>. + --> + +<resources> + + <string name="chanMode_RESTRICT_TOPIC_NAME">Restrict Topic</string> + <string name="chanMode_RESTRICT_TOPIC_DESCRIPTION">Only channel ops can edit the topic.</string> + + <string name="chanMode_BLOCK_COLORS_NAME">Block Colors</string> + <string name="chanMode_BLOCK_COLORS_DESCRIPTION">Messages containing color codes are blocked, as if the user was muted.</string> + + <string name="chanMode_STRIP_COLORS_NAME">Strip Colors</string> + <string name="chanMode_STRIP_COLORS_DESCRIPTION">All messages are stripped from color and control codes.</string> + + <string name="chanMode_ONLY_INVITE_NAME">Invite Only</string> + <string name="chanMode_ONLY_INVITE_DESCRIPTION">Only invited users can join the channel.</string> + + <string name="chanMode_ONLY_SSL_NAME">SSL only</string> + <string name="chanMode_ONLY_SSL_DESCRIPTION">Only users connected via SSL can join the channel.</string> + + <string name="chanMode_UNLISTED_NAME">Unlisted</string> + <string name="chanMode_UNLISTED_DESCRIPTION">The channel will not be listed anywhere.</string> + + <string name="chanMode_BLOCK_UNIDENTIFIED_NAME">Block Unidentified</string> + <string name="chanMode_BLOCK_UNIDENTIFIED_DESCRIPTION">Blocks unidentified users from joining the channel.</string> + + <string name="chanMode_PARANOID_NAME">Paranoid</string> + <string name="chanMode_PARANOID_DESCRIPTION">Disables the KNOCK command and the channel will not be shown in whois replies. Additionally, the channel won’t show up in listings.</string> + + <string name="chanMode_REGISTERED_NAME">Registered</string> + <string name="chanMode_REGISTERED_DESCRIPTION">The channel is registered with channel services.</string> + + <string name="chanMode_MODERATED_NAME">Moderated</string> + <string name="chanMode_MODERATED_DESCRIPTION">Blocks users without voice from talking.</string> + + <string name="chanMode_BLOCK_EXTERNAL_NAME">Block External</string> + <string name="chanMode_BLOCK_EXTERNAL_DESCRIPTION">Blocks users not in the channel from sending messages to it.</string> + + <string name="chanMode_ANTIFLOOD_NAME">Flood Protection</string> + <string name="chanMode_ANTIFLOOD_DESCRIPTION">Prevents users from flooding the channel with messages.</string> + + <string name="chanMode_PASSWORD_NAME">Password Protection</string> + <string name="chanMode_PASSWORD_DESCRIPTION">Users will have to enter a password to join the channel.</string> + + <string name="chanMode_LIMIT_NAME">Channel Limit</string> + <string name="chanMode_LIMIT_DESCRIPTION">Sets a maximum limit for users in the channel.</string> + + <string name="chanMode_REDUCED_MODERATION_NAME">Reduced Moderation</string> + <string name="chanMode_REDUCED_MODERATION_DESCRIPTION">Messages normally muted are still visible to ops.</string> + + <string name="chanMode_BLOCK_NOTICE_NAME">Block Notices</string> + <string name="chanMode_BLOCK_NOTICE_DESCRIPTION">Prevent notices from being sent to the channel.</string> + + <string name="chanMode_DISABLE_INVITE_NAME">Disable Invites</string> + <string name="chanMode_DISABLE_INVITE_DESCRIPTION">Prevents users from inviting others into the channel.</string> + + <string name="chanMode_AUDITORIUM_NAME">Auditorium Mode</string> + <string name="chanMode_AUDITORIUM_DESCRIPTION">Users can only see ops and themselves.</string> + + <string name="chanMode_QUIET_UNIDENTIFIED_NAME">Quit Unidentified</string> + <string name="chanMode_QUIET_UNIDENTIFIED_DESCRIPTION">Prevent unidentified users from sending messages.</string> + + <string name="chanMode_BLOCK_KICK_NAME">Block Kicks</string> + <string name="chanMode_BLOCK_KICK_DESCRIPTION">Prevents users from being kicked from the channel.</string> + + <string name="chanMode_PERMANENT_NAME">Permanent Channel</string> + <string name="chanMode_PERMANENT_DESCRIPTION">The channel is not deleted, even when all users leave.</string> + + <string name="chanMode_ONLY_OPER_NAME">IRC Operators Only</string> + <string name="chanMode_ONLY_OPER_DESCRIPTION">Allows only IRC Operators to join the channel.</string> + + <string name="chanMode_ONLY_HELPOPER_NAME">IRC Help Staff Only</string> + <string name="chanMode_ONLY_HELPOPER_DESCRIPTION">Allows only IRC Help Staff to join the channel.</string> + + <string name="chanMode_BLOCK_NICKCHANGE_NAME">Block Nick Changes</string> + <string name="chanMode_BLOCK_NICKCHANGE_DESCRIPTION">Prevents users from changing their nick while being in the channel.</string> + + <string name="chanMode_JOIN_THROTTLE_NAME">Limit Joins</string> + <string name="chanMode_JOIN_THROTTLE_DESCRIPTION">Sets a limit for how many users may join the channel per specified timespan.</string> + + <string name="chanMode_ALLOW_INVITE_NAME">Allow Invite</string> + <string name="chanMode_ALLOW_INVITE_DESCRIPTION">Anyone can invite users to this channel.</string> + + <string name="chanMode_BLOCK_FORWARDING_NAME">Block Forwarding</string> + <string name="chanMode_BLOCK_FORWARDING_DESCRIPTION">Prevent other channels from forwarding to this channel.</string> + + <string name="chanMode_ALLOW_FORWARD_NAME">Allow Forward</string> + <string name="chanMode_ALLOW_FORWARD_DESCRIPTION">Anyone can forward to this channel.</string> + + <string name="chanMode_BLOCK_ACTION_NAME">Block Action</string> + <string name="chanMode_BLOCK_ACTION_DESCRIPTION">Prevents users from using /me in the channel.</string> + + <string name="chanMode_BLOCK_CAPS_NAME">Block Caps</string> + <string name="chanMode_BLOCK_CAPS_DESCRIPTION">Prevents users from sending all-caps messages.</string> + + <string name="chanMode_BLOCK_KNOCK_NAME">Block Knock</string> + <string name="chanMode_BLOCK_KNOCK_DESCRIPTION">Prevents users from using /KNOCK to request an invite.</string> + + <string name="chanMode_CENSOR_NAME">Enable Badwords Filter</string> + <string name="chanMode_CENSOR_DESCRIPTION">Uses the network censor to block messages containing blocked words.</string> + + <string name="chanMode_HIDE_JOINS_NAME">Hide Joins</string> + <string name="chanMode_HIDE_JOINS_DESCRIPTION">Users are hidden until they speak.</string> + + <string name="chanMode_BLOCK_REPEAT_NAME">Block Repeat Messages</string> + <string name="chanMode_BLOCK_REPEAT_DESCRIPTION">Prevents users from sending the same message repeatedly.</string> + + <string name="chanMode_BLOCK_AUTOREJOIN_NAME">Block Autorejoin</string> + <string name="chanMode_BLOCK_AUTOREJOIN_DESCRIPTION">Prevents users from automatically joining after they have been kicked.</string> + + <string name="chanMode_IS_SECURE_NAME">Secure Channel</string> + <string name="chanMode_IS_SECURE_DESCRIPTION">All users in the channel are joined via SSL.</string> + + <string name="chanMode_BLOCK_CTCP_NAME">Block CTCP</string> + <string name="chanMode_BLOCK_CTCP_DESCRIPTION">Block CTCP messages from the channel.</string> + + <string name="chanMode_ONLY_ADMIN_NAME">Admin Only</string> + <string name="chanMode_ONLY_ADMIN_DESCRIPTION">Allow only IRC admins to join the channel.</string> +</resources>